In this post, I want to share my experience building a content management solution for a Grails application using Adobe AIR and XML bundles. This solution allows semi-static content to be kept externally. Main benefits are ease of deployment and desktop integration.
The Problem with Semi-static Content in Grails domain objects
Back when I was working for Mindblossom, I explored using Grails domain objects to build content management views for content-intensive websites. This approach worked fine as long as the content we were mapping were fairly deep and consistent. A list of wines, travel destinations or babecues usually had a set of attributes that were well known and defined prior to building the application.
There were two types of data, however, that constantly gave us problems.
- Products with arbitrary attributes: Many of these features were optional and not well-mapped. For a large automotive manufacturer, for example, these attributes would change from year to year and model to model. Adjusting to them would either mean building a robust dynamic attribute management system into the domain model ( complex ), or extending the domain model each time a new product arrived.I remember long nights at work when a client would send us car information at the last minute, and hearing cursing in German from across the desk from the poor guy that was constantly changing our domain models to match the new information.
- Information was that used to support user-interface elements. Page information needed for SEO, structured information needed for just a handful of pages, etc. This information was too big to keep in configuration files and didn’t warrant building a specific Grails domain object for them.
Two questions always came up when we were discussing pure Grails domain object-based CMS solutions. Our slick talking sales and product people will always talk their way around them with clients, but they always left a nagging question in my head as a technologist.
- Deployment. How are we going to ensure that we’re testing content with at least a similar set of values? While this didn’t matter much for product information, it was important for UI content that was constantly updated and changed. Can we make changes without re-deployment?
- Flexibility. The second one was flexibility. Despite all the advances in Grails, GORM and its hibernate based infrastructure still statically maps domain objects to databases. This infrastructure is heavily biased towards initial development. If I was building my own application from scratch, adding or removing attributes simply means changing my domain object and redeploying. To maintain this form of development, however, would mean that we would have to use a tool like autobase to manage database changes.
A Sketch of our current Editorial Content solution
When I first arrived at Pixsta and started working on the Empora fashion search website, we already had an editorial solution in place based on XML bundles and Plain Old Java Objects. Any content that was not classified as product information was kept in XML files that were pulled in by the Grails application.
At first, this system seemed a little clunky. As a geek, it was very hard to resist solving the problem by throwing more technology at it. We could solve the XML bundle problem by using a schema-less NoSQL solution like CouchDB. Then we can store all this stuff in a database!
As I got to work with this setup for the next few months, I began to appreciate the simplicity of this design. Having XML bundles stripped a database dependency for content that was constantly changing. We could deploy new versions of this content by simply copying this information over. If you have ever worked with external images in Grails applications, this was the same mechanism, except that instead of just jpg and png files, you were moving structured data that contained information about views and products.
I have nothing good to say about the POJO part of the implementation. It worked, but adding a new attribute would involve modifying both the POJO and the XML serializer it used to convert the XML into something usable by Groovy. Over the next few months, we quickly migrated the POJO solution to a simple Groovy XML slurper solution, where the data structure would be loosely defined as an XML document that was passed around.
At the end, we ended up with a system for editorial content that looked like this:
We still kept our important product information in a database and performed our proprietary image search operations on them, but this setup allowed us to add additional editorial content to results based on the request URL. Our Grails controllers simply aggregated the information that best fit in a database with the information from the XML files.
Building a CMS
Our editorial content solution worked for the most part. However, because the editorial information was kept in XML files, it meant that our content team was constantly editing XML files by hand. This was not good. We saw encoding errors, malformed XML and problems that arrived from copy and pasting from Word files.
Our next task was to build a Content Management solution to handle this editorial content. Most of our content already lived in the form of XML files and local files. We wanted a platform that could easily be updated, allow us to use existing skills in-house and be easy to extend. We chose Adobe Air.
Benefits of Adobe AIR
After considering a web-based Grails approach, Griffon/JNLP and Adobe AIR, we settled for Adobe AIR for the following reasons.
- Direct access to the file system.
- Already know AIR / Flex programming.
- Easy to update via the automatic update mechanism.
- E4X support for XML editing.
- No need convert XML to domain objects.
- Good library of direct UI Manipulation Libraries.
A few screenshots of the CMS:
After about two weeks of work ( sandwiched between other priorities ), I had written an initial version of our editorial content CMS. It had a few interesting features:
- Direct image map manipulation using the ObjectHandles library – I wrote a simple imagemap renderer that allowed our content team to define and edit existing imagemaps and generate the necessary HTML.
- Automatic updates – Adobe AIR provides an automatic update mechanism, it enables changes to made quickly and pushed out to clients ( think JNLP ). This proved very useful in the initial use of the content tool, as it allowed us to make changes to the CMS independent of other product tools. It also enables us to extend the CMS quickly whenever new features are added to the web application.
- Read and write from XML – instead of converting objects into ActionScript objects, I simply used e4x. This allowed me to quickly map XML fragments to ActionScript components and edit files directly.
- Links to image and content check directories. One of the benefits of a custom CMS is to be able to create links to a data test bed. The CMS had direct links to a staging server that pointed to the data being edited directly. This allows our content team to see their data exactly as it would appear live. This functionality also means less changes to the web application, since there was not a messy cycle needed to support preview and direct GSP manipulation.
- File Locking – added a simple file lock wrapper around each file being edited. Since our content team is small, the chances of the same people editing the same file was very slim. A file-based lock would simply notify them that the file was being edited by someone else.
Lessons Learned In This Approach
- Sometimes, the database is just not the right solution.
- Deployment as static files is much easier than from a database.
- Configuration files can be made much easier by externalising into files as well.
- Web services get more complicated, but not by much.
- It doesn’t take that much time. With a pure server-based approach, you have to constantly worry about migrating data, deploying and setting up the right infrastructure. Sometimes simple is better.
- Auto-update is a joy.
Possible Helpful Grails Plugins if you want to do it yourself
In the course of investigating this solution, I came across a few plugins that could potentially make this process easier. None of these plugins were used in this solution because our infrastructure already supported most of this functionality. But I would definitively consider these when starting a new project where I would be creating a new set of dynamic attributes from scratch.
- Static Resources Plugin – Runs a web service that deploys your static content as an XML file. Combined with the new XML form creation features of Flash Builder 4, this might allows us to use client-side scaffolding of data.
- XSL Transformation Tag – Allows you to apply a XSLT to a XML fragment and render into a GSP view.
- Export Plugin – Enables the export of grails data into other formats like Excel.
- Weceem – A CMS that provides a easy way to manage changing content. If Weceem had attribute management, most of these problems would go away.
- Gorm-couchdb – Another approach would be for to use the AIR app to connect to couchDB and have our grails app retrieve the data it needs via CouchDB. However, this still has the drawback of statically mapping our domain objects to a database definition.
Static Content Wish List
So what would make managing this semi-static content easier? I can see a couple of plugins that might make all the work and effort done here obsolete:
- A Data export / import plugin. A simple plugin that would enable backing up and exporting a grails project done at the UI level.
- A Dynamic Attribute Management Plugin. A plugin that will allow for the creation and management of domain object attributes at runtime.
I like this approach much better than a pure Grails approach. Content management, to me, fits better within a client. Using Flex and Air means that I would be able to re-use many of the display components. It enables separating the portions of the web application used for display and the tools needed to edit these.
There are many usability benefits available to a desktop interface: drag and drop of files into the editor, ability to save drafts and revisions via the built-in SQLLite database and offline/online content synchronisation.
Moreover, compared to a CMS built purely in Grails GSPs, a system like this can be built to edit GSPs and domain objects on the fly without worrying about application re-loading and making dramatic changes to Grails core.
I still would like to see a robust attribute management mechanism similar to the one available for Elastic Path.
It would also be interesting to start experimenting with either a Griffon or AIR-based desktop application for managing Grails content for the Weceem CMS ( I can dream, can’t I? ).
Maybe someday I’ll find time ( or a sponsor ) to write one.