I just finished putting the finishing touches on phase one of our video and animation heavy Flash / Grails / Flex site. We spent about 2 months on this site, figuring out how to get Flex, Flash and Grails to work together nicely, and I thought I would share some of the lessons learned in this post.
The application is a brochure-ware product that features rotating grills, and is back-ended by a Grails CMS. Grails was chosen over other toolkits like the Microsoft Community Server and Expression Engine because it provided the flexibility we needed to tackle a highly customized Flex RIA. Grails also allowed us to provide multiple views of our content for search engines and non-Flash customers.
Architecturally, our app is
Grails — talks to —> Flex —-> talks to —> Flash —-> talks to —> Flex
This is what I learned:
Lesson 1: Spend time in your build and deploy tools – it’s worth it.
Maven support for Grails is clunky, but it’s worth all the trouble to figure out. For this project, I had to:
- write a Macports port file for Grails
- figure out how to integrate the Grails-maven plugin with Cargo
- learn how to add grails projects into Hudson
- write a build template engine in GMaven
But it was worth it. By using all our tools, we were able to:
- Get set up faster: MacPorts allowed installing Maven and Grails on our macs a matter of just calling 2 commands. All our java dependencies and build commands were inside our Maven pom file. We didn’t have to track down any libraries, and it took less than an hour to get them from nothing to checking out from svn and running our app.
- Develop faster: because Maven allowed us to build our flex applications with one command, we would have our localhost running with grails run-app, and just call a mvn generate-sources each time we changed our flash / flex files. Grails 1.1 promises improved maven plugin support. That is going to rock.
- Build faster: one line = build all flex files + build all grails files + generate a war file + test this war file + deploy + run it in a web application container. It was magical. Now if we could only compile Flash.
- Test faster: Hudson and Cargo integration in Maven meant instant deployment of our changes into test machines. QA could do its job and we would get mad props from the chief.
- Deploy faster: We stored build profiles in Maven, which allowed us to build our deployment wars without having to remember specific information. Cargo support means that the deploy to production step could eventually be automated. But for security reasons, we do it by hand.
Lesson 2: Grails REST services beats BlazeDS. To a bloody pulp.
The Grails-Flex plugin. What a wonderful idea. I got giggles playing with Marcel’s hello world example.
But then came trying to get it to work with non-toy data. Hibernate breaks when trying to handle many-to-one relationships, something about the connection being closed. Then you had to create new Actionscript objects for each of your domain classes, replicating a lot of the work. Then it was slow when you had a lot of objects, a lesson we learned from the monster called Cairngorm.
Our solution, keep it light. We used simple REST services with Grail’s content negotiation capabilities; and we didn’t run into those nasty hibernate session exceptions anymore. We kept everything in a native XML format and used e4x to bind this data into our components; and it was beautiful, elegant and powerful. Both Grails/Groovy and Flex/ActionScript have incredible XML support; exploit this.
Lesson 3: Keep Two Sets of Books for Navigation and Deep Linking.
We used grails to generate a basic page for search engines, so when someone navigated to site/grills/show/3, for example, they will see the content of the SWF page displayed in HTML if they didn’t have flash player installed.
One of the challenges was to allow for this to work, and at the same time have our traditional Flash browser manager’s support for the back button and deep linking to work as well. Our solution involved allowing urls of the form
when our navigation actionscript tries to resolve this, it will show you controller 2 and item id 2.
But if you left the fragment ( http://www.mysite.com/grills/show/4 ) empty, then the navigation will resolve grills to be right controller and item number 4.
Essentially, this meant that if a web crawler indexed a feature of our grill (number 4), then the person will see this grill displayed in the swf file when they come in. As they click within the swf file, all their new navigation changes will be tracked by Flash’s BrowserManager mechanism.
Lesson 4: Grails is an awesome CMS to manage Flex assets.
We started off storing images on the server. Then we started storing off states. Eventually, instead of writing pure domain classes that always had an on and off image and some text, we wrote a simple FlexResource domain class in Grails that will be associated with a Renderer in Flex actionscript. Then we started thinking about storing swf pieces in our Flex CMS.
The trick was to store references to chunks of SWF files on the server, and then load them as needed in our main Flex file. This meant that adding a new grill will no longer need a compilation of the swf, but rather it could be added to the server and loaded dynamically via the ActionScript SWFLoader.
We discovered this technique almost by accident. We constantly had over and down states in our flex buttons that needed to be managed. Then we started having resources that needed to fire off events. Eventually, we learned that it was a good idea to keep big chunks of self-contained Flash movies into swf files, and simply create communication ( localization and eventing ) hooks into these swf files.
For our next project, we will try to keep as much display content as possible in individual Flex / Flash swf files that know how to connect like lego blocks ( using the localconnection interface ).
Lesson 5: Keep animations in Flash. Keep text and navigation in Flex. Manage it all in Grails.
Flash is amazing when you have to do complex graphics like our BBQ animations, but it has an abysmal text / localization / navigation support.
Flex has really good navigation and support for HTML-like containers, but it’s hard to draw things in it.
Grails can handle great amounts of data in a robust, secure and scalable way. But GSPs are hard to make work universally across browsers.
By putting them together, you get the best of all worlds. You use grails to add new content and manage your data model. Use flex to handle navigation and basic things like image and text display. Use flash for robust graphics and animations.
Lesson 6: Grails loves XPath. Flex ActionScript, not so much.
Flex handles XML. Grails gives XML. The world is happy and peaceful and unicorns frollick in the woods.
Then the first exceptions come.
One of the gotchas of the Grails deep XML converter is that instead of returning an entity twice, it will return a XPath reference for the second instance. Unfortunately Flex Xml support does not handle references very well. I first tried a free XPath library, but that kept giving me SWF errors. At the end, I ended up writing my own reference resolver, which solved my problem.
Another problem is that while e4x allowed me to delete child references and replace them with another XML. But then it caused some nasty errors when the XML was referenced again. So we had to make copies of XML blocks that contained references and link them into the right components.
So not the most perfect implementation, but very close. If the project was more complicated, I would definitively try to make the XML pieces generated by Grails as small as possible ( i.e. loading a grills detail in XML rather than the entire list of grills ).
Lesson 7: Love the Bootstrap file.
Editing the Grails bootstrap file may seem like a nightmare. Until you realize that you are no longer creating tables in mySQL. For our project, there was a ton of creative content change. Images were replaced, hearts were broken, titles and description were thrown around everywhere and discarded. Stylesheets were constantly being reinvented and hotspots and grills will apper and vanish at the whim of the higher ups. Until we get a better project management process ( zing! ), being able to initiate and keep this data in the bootstrap file was a joy.
Lesson 8: Love Plugins even more!
The beautiful thing about grails was that there are a ton of plugins to help make the backend more robust. The Java-ness of Groovy means that there are a ton of proven enterprise solutions like Lucene and Acegi security ready to be exploited for projects. Need an image handler? There is ImageTools. Need security? There is JSecurity! Rss Feeds? The Feeds Plugin! The high availability of Grails plugins means heavy re-use by lazy developers like me. Have I mentioned how much I like Grails?
Unfortunately, the Flex plugin seems out of commission and abandoned. In the near future, I hope to collect all these lessons and put them into a Flex-REST plugin. Stay tuned.
Lesson 9: Everything works out of the box. Almost.
Content Negotiation in Grails works marvelously – except in Firefox 3 because the accept header is not parsed correctly in grails.
The Flex 3 BrowserManager is the best thing since sliced bread – except when you’re using SWFObject because the history.js file assumes a certain embed/object format for the swf.
The Flex SWFLoaders can load SWF files seamlessly – except when you run into security zone issues or have different ActionScript versions.
Flex XML handling is a dream – except when dealing with XPaths and references ( see lesson 6).
Flash localconnection works magics – except when you already have one instance of the same swf open with the same id — you need to generate unique ids.
There are many little gotchas with new technology like this.
Another gripe might just be the lack of references for this stuff. With something like Rails, you can reference a book like Flexible Rails. But with Grails, we got almost nothing. ( So Apress, if you’re listening, I can write a Flexible Grails book for ya ;p. I swear it will be popular ). Rails even has a flex sdk. But then again, we might be working like mad trying to get mongrel clusters figured out and trying really hard to do Lucene and Solr integration.
Ultimately, working with a brand spanking new technology like Grails allows me to learn that patience and curiosity sometimes overcomes that desire to smash the screen in. Grails is a viable solution in a world of more mature frameworks like Django and Rails. The fact that Groovy talks well with Java and Grails is built on top of proven technologies like Hibernate/Spring allows it to become an ideal solution for shops with this expertise. I can’t wait to develop more Grails / Flex / Flash projects!