mardi 6 juillet 2010

Flex / Grails CRUD application with GraniteDS, reloaded

Now with Flex 4, Spring Security 3, data push...

It's been almost one year since the last blog entry about the gdsflex plugin. We have just released the version 0.8 of the plugin that brings compatibility with all new releases of the various technologies involved: Grails 1.2/1.3, Flex 4, Spring Security 3... It's time to update the tutorial for this whole new stack.

For the purpose of this article, I'll just write the same boring book application that I've demonstrated before, and simply add additional capabilities: security and data push.

The first important thing before starting is that you now need to install a Flex SDK somewhere and set the FLEX_HOME environment variable to point to its path. It you want to use a Flex 4, that will look like FLEX_HOME = /home/will/flex_sdk_4.
Older versions of the plugin used to embark a full Flex SDK for ease of use, but using FLEX_HOME allows for easier upgrades of the Flex SDK and is more in line with the behaviour of other Grails plugins.

You will also need Grails 1.3.1+ installed and set up (the plugin also works with Grails 1.2.2+ but that could need some minor adjustments in the following steps). Now type from the command line :

grails create-app bookmanager

cd bookmanager

grails install-plugin gdsflex

Part 1 : Define the domain classes and generate a scaffolded Flex application

Just as before, the core of the application is centered on Grails, and more precisely on the domain classes, following usual Grails domain-driven style. Once again we'll start by an Author class.

grails create-domain-class Author

package bookmanager

class Author {

static constraints = {
name(size:0..50, blank:false)
picture(nullable:true, widget:'image')

String uid

String name

Date birthDate

java.sql.Blob picture

And the corresponding controller, here using scaffolding for simplicity :
grails create-controller Author

package bookmanager

class AuthorController {

def index = { redirect(action:list, params:params) }

def scaffold = Author

This is not much different from the previous blog examples. Just notice how Grails 1.3 automatically puts domain classes and controllers in a package with the same name than the application.
As always the TideEnabled annotation exposes the controller to the Flex client.

Now we can generate and compile the Flex application :
grails generate-flex-app

grails mxmlc

grails run-app

And go to http://localhost:8080/bookmanager/bookmanager.swf.

You can see a basic working Flex application that allows to create and edit authors. For now the generated app still uses Flex 3 Halo components and not Flex 4 Spark components, but it can perfectly be compiled and run with the Flex 4 SDK.
Future releases of the plugin will generate a Flex 4 Spark application.

What has happened ?
The generate-flex-app script has generated a basic mxml that handles CRUD operations using the Tide UI builder library in grails-app/view/flex/bookmanager.mxml.
The mxmlc script triggers the Flex compiler to build the application swf in grails-app/views/swf.

The Grails server is now started from this terminal, open a new terminal/command line editor to type the next commands.

Now let's add a couple of other classes with associations.
grails create-domain-class Book

grails create-domain-class Chapter

grails create-controller Book

package bookmanager

class Book {

static constraints = {
title(size:0..100, blank:false)
category(inList:["Fiction", "Non-fiction", "Biography"])
description(size:0..2000, widget:"textArea")

String uid

String title

String category

Author author

Set chapters

String description

static hasMany = [ chapters:Chapter ]
static mapping = {
author fetch:"join"
chapters cascade:"all-delete-orphan"

package bookmanager

class Chapter {

static constraints = {
title(size:0..50, blank:false)

String uid

Book book

String title

String summary

static mapping = {
book fetch:"join"

package bookmanager

class BookController {

def index = { redirect(action:list, params:params) }

def scaffold = Book

An important thing is that ManyToOne associations must be marked fetch:"join" or lazy:false. GraniteDS does not support transparent lazy loading for single ended associations, and most likely never will (it would generate unacceptable network and database traffic, one http request and one SQL query for each uninitialized entity). Lazy collections are supported, so OneToMany and ManyToMany associations do not have to be marked lazy:false.

Once the domain classes written, we can generate their Flex ActionScript 3 equivalents with :
grails gas3

An add a Book entry to the main menu in grails-app/view/flex/bookmanager.mxml.
<mx:LinkButton label="Books" width="100%" textAlign="left"
click="mainStack.selectedChild = bookUI" />
<ui:EntityUI id="bookUI"
width="100%" height="100%"/>

I won't get into much details about the EntityUI stuff. It comes from the built-in Tide UI builder library that enables the dynamic client-side scaffolding.
For real applications, you should write your own Flex UI to obtain a really rich and usable interface. The auto generated application can be mostly seen as a quick and dirty prototype.

We can now create and edit books, and see how many-to-one and one-to-many associations are displayed in the generated application.

If you eventually tried to add chapters, you will see that it does not work. There are indeed two minor changes to do manually in the AS3 classes to help the UI builder make the link between the associated oneToMany entities: initialize the Chapters collection in the class, and add a constructor in :

public function Book():void {
chapters = new ArrayCollection();

public function Chapter(book:Book = null):void { = book;

Once these changes are made, just refresh the browser and check that you can add chapters to your books. Notice how the Gas3 generator and the Flex compiler have been triggered automatically in the background in the running Grails window.

Part 2 : Securing the application

In a real application, it would required that only authenticated users can access enterprise data. Since 0.8, the gdsflex plugin supports the spring-security-core plugin that integrates with Spring Security 3.

Stop the Grails server, and install the plugin with :
grails install-plugin spring-security-core

Then generate the security domain classes Person and Authority (I don't know why, other class names have not worked with the spring-security-core 0.4.1) :
grails s2-quickstart bookmanager Person Authority

The security plugin has generated 3 domain classes : Person, Authority and PersonAuthority. As we have not configured a real database, we are simply going to add a bootstrap script to create default users and roles for our application.

import bookmanager.Person
import bookmanager.Authority
import bookmanager.PersonAuthority

class BootStrap {

def springSecurityService

def init = { servletContext ->

def user_admin = new Person(username:"admin",
password: springSecurityService.encodePassword("admin"),

def user_user = new Person(username:"user",
password: springSecurityService.encodePassword("user"),

def role_admin = new Authority(description:"Admin",
def role_user = new Authority(description:"User",

new PersonAuthority(person:user_admin, authority:role_admin).save()
new PersonAuthority(person:user_user, authority:role_user).save()

def destroy = {

Now we need to secure access to the application and add a login page. We will make use of the built-in Tide identity component and define a ViewStack to display/hide the login page depending on the current authentication state.

Here's the relevant code to add to grails-app/views/flex/bookmanager.mxml :

import org.granite.tide.spring.Identity;


[Bindable] [Inject]
public var identity:Identity;

private var message:String;

private function loginResult(event:TideResultEvent):void {
message = "";

private function loginFault(event:TideFaultEvent):void {
message = event.fault.faultString;


<mx:ViewStack id="appView" selectedIndex="{identity.loggedIn ? 1 : 0}" width="100%" height="100%">
<mx:VBox width="100%" height="100%" verticalAlign="middle" horizontalAlign="center">
<mx:Panel title="Login"
verticalGap="0" paddingTop="8" paddingBottom="8"

<mx:FormItem label="Username">
<mx:TextInput id="username"/>
<mx:FormItem label="Password">
<mx:TextInput id="password" displayAsPassword="true"
enter="identity.login(username.text, password.text, loginResult, loginFault);"/>

<mx:Label text="{message}"/>

<mx:Button label="Login"
click="identity.login(username.text, password.text, loginResult, loginFault);"/>

<mx:VBox id="mainUI" width="100%" height="100%">
<mx:ApplicationControlBar id="acb" width="100%">
<mx:Label text="GraniteDS / Grails generated application" fontSize="18" fontWeight="bold" color="#f0f0f0"/>
<mx:Spacer width="100%"/>
<mx:Label text="Logged in as {identity.username}"/>
<mx:Button label="Logout" click="identity.logout()"/>



There is nothing very sophisticated here, just notice how we make use of the identity.loggedIn property to display the correct UI and identity.login/identity.logout to trigger user login/logout.

You can restart the application, and check that you can log in with the admin/admin and user/user usernames and passwords combinations (and obviously not with others).

Note that we could also have relied on the default html login page of the spring-security-core plugin to secure the application and protect access to the swf itself. That would be the way to go to enable OpenID authentication or any other Web-based authentication model. In this case, you don't necessarily have to add a Flex login page, but you have to indicate to Flex that it has to retrieve the authentication state at startup with something like :
<mx:Application creationComplete="identity.isLoggedIn()" ... />

This can also be used to allow the authentication state to be restored after a browser page refresh.

We can now try to add more advanced authorization filtering. Let's say that we want to forbid deletion of authors by non-administrator users. This requires a few steps :

1. Enable authorization support in grails-app/conf/GraniteDSConfig.groovy

graniteConfig {
springSecurityAuthorizationEnabled = true
springSecurityIdentityClass =

This tells GraniteDS to enable integration with Spring Security authorizations and defines the Identity3 integration class for Spring Security 3 (the one used in the spring-security-core plugin).

2. Use the Identity component

Usually you will use the Identity component with Flex data binding on component properties such as visible or enabled to hide/disable parts of the UI depending on the user access rights.
For example this will define a button that is displayed only to administrator users :
<mx:Button label="Delete" visible="{identity.ifAllGranted('ROLE_ADMIN')}" includeInLayout="{identity.ifAllGranted('ROLE_ADMIN')}"/>

In our example, it will be a bit more tricky because we use the automatic Tide UI builder. We have to override the default mxml for authors and manually set the data binding for the visible and includeInLayout properties.

import mx.binding.utils.BindingUtils;
import org.granite.tide.spring.Identity;

public var identity:Identity;

protected override function layoutForm():void {

BindingUtils.bindProperty(this.buttonBar.getChildAt(1), "includeInLayout", identity,
{ name: 'ifAllGranted', getter: function(identity:Identity):Boolean { return identity.ifAllGranted('ROLE_ADMIN'); } }
BindingUtils.bindProperty(this.buttonBar.getChildAt(1), "visible", identity,
{ name: 'ifAllGranted', getter: function(identity:Identity):Boolean { return identity.ifAllGranted('ROLE_ADMIN'); } }

And the override in the main mxml :

Spring.getInstance().addComponentWithFactory("", AuthorEdit,
{ entityClass: Author }, true, true, Tide.RESTRICT_UNKNOWN, null, false);

Now if you restart the application, you can check that the Delete button is displayed only when you are logged in as administrator.
Note that user authorizations are retrieved from the server the first time, but are then cached locally, so it's not expensive to add as many ifAllGranted as you wish in the application.

Part 3 : Enabling data push for the application

We can now securely display, create, edit and delete our data. The last advanced feature of GraniteDS that I will show in this post is the data push that allows data updates to be propagated in near real-time to other users.
Once again it involves a few steps :

1. Configure a Tomcat NIO connector

The default Tomcat configuration included in Grails 1.2+ does not use a NIO connector. Using the NIO connector is recommended for GraniteDS data push to provide the better scalability.
It is possible to use the default connector during development but the NIO configuration is interesting (as an aside, thanks to John Fletcher for having taken the time to dig this from the deep of the Grails mailing list, see here:
In scripts/_Events.groovy, add this :
import org.apache.catalina.connector.Connector;

eventConfigureTomcat = { tomcat ->

def nioConnector = new Connector("org.apache.coyote.http11.Http11NioProtocol")
nioConnector.port = 8081
nioConnector.setProperty("redirectPort", "8443")
nioConnector.setProperty("protocol", "HTTP/1.1")
nioConnector.setProperty("enableLookups", "false")

tomcat.service.addConnector nioConnector

Then you will have to access the application with http://localhost:8081 instead of the standard port 8080.

Note that for production use, it is highly recommended to use the native APR connector, see in the Tomcat documentation here for more information.

2. Enable Gravity/push support in grails-app/conf/GraniteDSConfig.groovy

graniteConfig {
springSecurityAuthorizationEnabled = true
springSecurityIdentityClass =

gravityEnabled = true
dataDispatchEnabled = true

3. Define a Gravity channel and destination

Then we have to define a Gravity channel and topic in the services-config.xml Flex configuration:

<service id="granite-service"

<destination id="spring">
<channel ref="my-graniteamf"/>

<service id="gravity-service"
<adapter-definition id="simple" class="org.granite.gravity.adapters.SimpleServiceAdapter"/>

<destination id="bookManagerTopic">
<channel ref="my-gravityamf"/>
<adapter ref="simple"/>

<factory id="tideSpringFactory" class="org.granite.tide.spring.SpringServiceFactory">

! Declares my-graniteamf channel.
<channel-definition id="my-graniteamf" class="mx.messaging.channels.AMFChannel">

<channel-definition id="my-gravityamf" class="org.granite.gravity.channels.GravityChannel">

4. Configure the Flex client application to use the topic


// Register a data observer component with the name of the topic
Spring.getInstance().addComponent("bookManagerTopic", DataObserver, false, true);
// Binds the subscribe and unsubscribe methods of the component to the application login/logout events
Spring.getInstance().addEventObserver("org.granite.tide.login", "bookManagerTopic", "subscribe");
Spring.getInstance().addEventObserver("org.granite.tide.logout", "bookManagerTopic", "unsubscribe");

5. Configure the controllers to handle dispatch of data updates

Just add the following annotation to all the controllers of the application :
@DataEnabled(topic="bookManagerTopic", params=ObserveAllPublishAll.class, publish=DataEnabled.PublishMode.ON_SUCCESS)

This references a parameter class that allows filtering of which update events can be dispatched. Here we will use an extremely simple filter class that filters nothing :


public class ObserveAllPublishAll implements DataTopicParams {

public void observes(DataObserveParams params) {
// Define key/value pairs that the client is able to observe
// Will be used to construct the topic selector for the client calling the component

public void publishes(DataPublishParams params, Object entity) {
// Define key/value pairs to add in the published message headers
// Will be used to match against the topic selector of the subscribed clients

Part 4 : Deploy all this as a war in Tomcat

Just run :

grails war

Then rename the generated bookmanager-0.1.war to bookmanager.war and copy it to the Tomcat webapps folder.
Ensure you have correctly installed the native APR connector, start Tomcat, and browse http://localhost:8080/bookmanager/bookmanager.swf, et voilà !

I will stop here for this article. We could go a bit further by adding conflict handling, or per-instance authorizations, but I let this for a future post.
Hopefully this article has shown the range of capabilities of the plugin and of the underlying GraniteDS Flex/Java integration library.

As always, don't hesitate to experiment all this and give your feedback.

22 commentaires:

J. Mammen a dit…

Excellent article, however when I tried it with latest Grails 1.3.3 and Flex 4 and JDK 1.6 it threw many errors.

Any idea if this is supported under flex 4,jdk 1.6 and grails 1.3.3

William Draï a dit…

What kind of errors do you get ? I've tested it with Flex 4, JDK 6 and Grails 1.3.3 without problem.

lh a dit…

Clever article indeed.
But I agree with @J.Mannen, it doesn't work 100%.

I tried it too (JDK1.6.0_18, Grails 1.3.3, Flex SDK

Here are errors :

1) EntityUI.mxml (line 251)

it needs :
dataProvider=_context.getItemAt("_entityName + 'List'")
instead of original one :
dataProvider="{_context[_entityName + 'List']}"

2) ManyToOneEditor (line 59/60/61)

it needs :
dataProvider="{_context.getItemAt("_elementName + 'InstanceList'")}"
selectedIndex="{_context.getItemAt("_elementName + 'InstanceList'].getItemIndex(property)")}"

instead of original ones.

3) it needs lowerCase for first letter of authorController instead of AuthorController (which is annoying...)

It could become a great solution (compared to Blazeds) if these pbs are solved.

Thanks in all cases.

William Draï a dit…

The messages about context[] not being bindable are simply compiler warnings and don't prevent the application from working. I don't think your fix with getItemAt will work (there is no getItemAt method on context).

I don't understand your point 3 about lowercase. Is it on the Groovy class or in ActionScript ?

lh a dit…

I don't know much about your plugin as it is your plugin !

I tried it following your article.

Bug at the very beginning :
_ Error 2048 and only a loader gif and nothing....

Indeed, there are compiler warnings.

Without fixing them, it doesn't work.. at all !!

After a first fix in flex files, them flex starts normally.

But after that, it works with difficulties :
_ A form without fields one time over two...
_ An error message about AuthorController (flex or grails/graniteds/flex is waiting for "authorController" instead of "AuthorController" class ...

Without a new fix, it doesn't do anything when trying to save...
Then finally... it seems to work 50%... Reloading flex app url to get an Author form with all fields...

"My fixes" (raw emergency debugging) work as it was the only way to start app !!

but the result after that is finally not so good... (;-(

I don't know what to think about this plugin.
Is it just a question of fixing last bugs or a deeply bad impedance architecture issue ?

William Draï a dit…

Very strange indeed. It has maybe something to do with Flex 4.1, I've tested only with the latest Flex 4.0.
Thanks for your feedback, I'll have a look.

William Draï a dit…

Still no luck, everything works with Flex 4.1, JDK 1.6.0_21 and Grails 1.3.3 on a freshly installed Windows box.
Which OS are you using ?

lh a dit…

I use Windows 7, Firefox 3.6.6.

Vlastimil a dit…

It really doesn't work. There is a lot of compilation errors from Flex. I'm using Grails 1.3.2 and Flex 4.0.

Vlastimil a dit…

Sorry, it works now. I deleted whole project and the new one is OK... I really don't know what was wrong, the only thing what i don't see in your guide is "import mx.collections.ArrayCollection;" in

Tony Lim a dit…

I'm getting the following error when adding AuthorEdit.mxml to bookmanager.mxml.

any ideas why?

\NetBeansProjects\bookmanager\grails-app\views\flex\bookmanager.mxml(55): Error: Access of undefined property Tide.

{ entityClass: Author }, true, true, Tide.RESTRICT_UNKNOWN, null, false);

Mahesh Desai a dit…

Hey William.. Thanks for posting this interesting stuff. I am trying to follow steps from your blog but it gives me flex compilation errror... my environment is Mac Os, flex_sdk_4.1.0.16076, jdk 1.6 and grails 1.3.4 but it is throwing me below error.... Can you please tell me what I am doing wrong??

Caused by: org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed:
FlexCompiler: 32: unable to resolve class
@ line 32, column 1.

FlexCompiler: 31: unable to resolve class
@ line 31, column 1.

William Draï a dit…

@Tony just add
import org.granite.tide.Tide;

@Mahesh are you sure you have correctly defined your FLEX_HOME environment variable

Jalex a dit…

I tried this example in Windows 7, Grails 1.3.4 and flex 4.1.
After solving problem with imports
.It works but after puting some datas
the fields of the forms Author and Chapter disapear.
It returns only after restarting the App.

Syam a dit…

I am using groovy and grails as back end and flex as front end.
For a new Project, i have the gdsflex plugin (0.8.3) installed by
using netbeans ide (6.8). I have created domain classes and
controllers.. But i Can't RUN the project. compilation and war file
creation are successfull. The Grails version used is 1.3.5. Groovy
version used is 1.6.4. FlexSDK used is flex_sdk_4.0. The below shown
is the error description.. Please Help me.. pls...

Running Grails application..
2010-11-10 12:56:14,291 [main] ERROR context.GrailsContextLoader -
Error executing bootstraps: null
at GdsflexGrailsPlugin
at GdsflexGrailsPlugin
at grails.spring.BeanBuilder.beans(
at grails.spring.BeanBuilder.invokeMethod(
at org.grails.tomcat.TomcatServer.start(TomcatServer.groovy:
at grails.web.container.EmbeddableServer$
at _GrailsRun_groovy
at _GrailsRun_groovy
at _GrailsSettings_groovy
at _GrailsSettings_groovy
at _GrailsRun_groovy$_run_closure5.doCall(_GrailsRun_groovy:
at _GrailsRun_groovy$
at _GrailsRun_groovy.runInline(_GrailsRun_groovy:116)
at _GrailsRun_groovy.this$4$runInline(_GrailsRun_groovy)
at _GrailsRun_groovy$_run_closure1.doCall(_GrailsRun_groovy:
at RunApp$_run_closure1.doCall(RunApp.groovy:33)
at gant.Gant$_dispatch_closure5.doCall(Gant.groovy:381)
at gant.Gant$_dispatch_closure7.doCall(Gant.groovy:415)
at gant.Gant$_dispatch_closure7.doCall(Gant.groovy)
at gant.Gant.withBuildListeners(Gant.groovy:427)
at gant.Gant.this$2$withBuildListeners(Gant.groovy)
at gant.Gant$this$2$withBuildListeners.callCurrent(Unknown
at gant.Gant.dispatch(Gant.groovy:415)
at gant.Gant.this$2$dispatch(Gant.groovy)
at gant.Gant.invokeMethod(Gant.groovy)
at gant.Gant.executeTargets(Gant.groovy:590)
at gant.Gant.executeTargets(Gant.groovy:589)

slysiou a dit…

Syam, I use STS and I am in same situation. Help needed ...

Syam a dit…

hi slysiou,

if you have the same problem then try installing gdsflex 0.8.2 plugin. It will be the problem of versions.. By doing this my problem had been solved.. Just check it.......

Regards Syam.

slysiou a dit…

Thanks a lot Syam, Version 0.8.3 doesn't work and Version 0.8.2 works fine !

slysiou a dit…

upgraded to last version (0.8.4). Bug fixed and everything works fine !

kwame a dit…

Hello William, Hello slisiou, Hello Everybody.
The tutorial is excellent.
Many thanks to William for taking time to develop a so great plugin.
But It would be very helpful if you could explain step by step how to integrate it with Flashbuider 4 in
order to not to have to write by hand the mxml code.
I was following the example tutorial on the plugin's site.
I have succefully created the grail app example; after that I fire my Flashbuilder 4 trying to create a project named: example but what to set as Project folder? What to set as application server type (none,J2EE..)? create combined Java/Flex project using WTP?
What to set as output folder etc...
Please, can anyone help me ???
Thank you in advance.

felipe a dit…

Hi, I've tried running this example with grails-1.3.7, gdsflex-0.8.5 and flex 4, but when I run "grails mxmlc" I get a huge stacktrace saying:

at $Proxy8.loadGroovySource(Unknown Source)
at java.lang.ClassLoader.loadClass(
at java.beans.Introspector.instantiate(
at java.beans.Introspector.findExplicitBeanInfo(
at java.beans.Introspector.(
at java.beans.Introspector.getBeanInfo(
at Method)
at _GrailsFlexCompiler_groovy$_configureFlexCompilerClasspath_closure3.d
at $Proxy8.loadGroovySource(Unknown Source)
at java.lang.ClassLoader.loadClass(
at java.beans.Introspector.instantiate(
at java.beans.Introspector.findExplicitBeanInfo(
Error executing script Mxmlc: null

Anyone ever had this problem? Can anyone help?

Thanks a lot

BiMaWa a dit…

some trouble need help!!