Grails/BlazeDS/Flex/iPhone Full Stack Part 2/3

In the previous episode, we built a simple Grails backend for the todolist application. In this installment, we will create a simple Flex 4 front-end for this backend.

The following assumes that you have already installed Flash Builder 4 (formerly known as Flex Builder), either in standalone mode or as an Eclipse plug-in.

Part 2: Flex front-end

The first thing we need to do (that I showed you in the previous screencast) is to install the Grails BlazeDS plugin. In IntelliJ, right-click the todolist project and choose Grails Plugins:

In the dialog that appears, if the list is empty, click the Reload plugin list button in the top-left corner. Then select the blazeds plugin and click Apply changes:

Since Grails BlazeDS plugin depends on Spring-Security plugin, the latter is also installed automatically. So we need to configure security. Go to the Tools menu and select Run Grails target:

In the dialog that appears, type “create-auth-domains” then click OK:

This script will create three domain entities to handle the role-based security of our application. Users will be stored as Person instances, roles in Authorities and Requestmap makes it possible to specify which role has access to which URL. It also creates a SecurityConfig.groovy script in grails-app/conf. Before moving on, we will move the three generated entities to the org.epseelon.todolist package. To do that in IntelliJ, simple drag-and-drop the three classes to the package:

In the dialog that appears, leave the default options and click OK:

In the Refactoring Preview panel, right-click and exclude “Usage in XML descriptor” and “Usage in comments”, then click “Do Refactor”:

Now, all five domain classes reside in the same package and SecurityConfig.groovy has been updated:

security {

	// see DefaultSecurityConfig.groovy for all settable/overridable properties

	active = true

	loginUserDomainClass = "org.epseelon.todolist.Person"
	authorityDomainClass = "org.epseelon.todolist.Authority"
	requestMapClass = "org.epseelon.todolist.Requestmap"
}

Now since we are using an in-memory HSQL database, it is completely cleared up every time we start up the server. In order to avoid having to reconfigure default users and roles every time, we are going to add some initialization code to the grails-app/conf/BootStrap.groovy script:

import org.epseelon.todolist.Person
import org.epseelon.todolist.Requestmap
import org.epseelon.todolist.Authority

class BootStrap {

    def authenticateService

     def init = { servletContext ->

         Person.withTransaction {
             def me = new Person(
                     username: "sarbogast",
                     userRealName: "Sebastien Arbogast",
                     passwd: authenticateService.encodePassword("password"),
                     enabled: true,
                     email: "sebastien@epseelon.com"
             )
             me.save()
             def adminAuth = new Authority(
                     description: "administrator",
                     authority: "ROLE_ADMIN"
             )
             adminAuth.save()
             me.addToAuthorities(adminAuth)
             def userAuth = new Authority(
                     description:"user",
                     authority: "ROLE_USER"
             )
             userAuth.save()
             me.addToAuthorities(userAuth)
             def projectMap = new Requestmap(
                     url: '/project/**',
                     configAttribute: 'ROLE_USER, ROLE_ADMIN'
             )
             projectMap.save()
             def todoMap = new Requestmap(
                     url:'/todo/**',
                     configAttribute: 'ROLE_USER, ROLE_ADMIN'
             )
             todoMap.save()
             def personMap = new Requestmap(
                     url:'/person/**',
                     configAttribute: 'ROLE_ADMIN'
             )
             personMap.save()
             def authorityMap = new Requestmap(
                     url: '/authority/**',
                     configAttribute: 'ROLE_ADMIN'
             )
             authorityMap.save()
             def requestmapMap = new Requestmap(
                     url:'/requestmap/**',
                     configAttribute: 'ROLE_ADMIN'
             )
             requestmapMap.save()
         }

     }
     def destroy = {
     }
} 

This code basically creates one user, two roles and five authorization patterns and connects all that together. With that in place, we can start up our application again using the Build configuration. And when the application appears in the browser, you can try to create a project (http://localhost:8080/todolist/project/create) and you should be redirected to the login page:

Of course you can login and check that you can create projects and todos and so on.

This is where the first screencast ends. Now that security is configured, let’s move on to creating a Flex project.

Flex project

Before creating the Flex project, the first thing we need to do is start up the Grails application in WAR mode. To do that, edit build configurations in IntelliJ, duplicate the configuration that runs run-app and set run-war as the command line to execute. Don’t forget memory parameters:

Then run this build configuration and wait for the server to be started. Of course you have to shut down the server first if it was already running.

In Flash Builder, right-click in the Package Explorer view and select New>Flex Project:

In the dialog that appears, set the name of the project to “todolist-web”, select “Web” as the application type (default), choose Flex 4 as the Flex SDK version (use default SDK), choose J2EE as the application server type and choose BlazeDS as the remote object access service. Then click Next.

In the next step, set Root folder to “/Users/sarbogast/.grails/1.2.2/projects/todolist/war” (this is where grails run-war deployed our backend application in exploded WAR mode), root URL to “http://localhost:8080/todolist/”, context root to “todolist” and hit “Validate configuration”. If everything is OK and your server is running correctly, you should have a message saying “The web root folder and root URL are valid”:

Output folder should have been set automatically and you can click Finish. When the project is created and the content of Main.mxml appears, go to the Data/Services view at the bottom, and click “Connect to Data/Service…”:

In the dialo that appears, select BlazeDS and hit Next:

When we installed Grails BlazeDS plugin, it exposed an EchoService service to allow us to check that communication is working between the Flex client and the Grails backend. Select this echoService and hit Finish:

What this does is generate client-side stubs for the echo service. You then have a new entry in Data/Services view:

To test that it is working, right click “echo(arg0: String) : String”, and select “Test Operation…”:

In the Test Operation view that appears, if you click Test right away, you will get an “Access denied” error because this method is only accessible to ROLE_ADMIN users and we are not even authenticated:

To fix that, we need to check the “Authentication required” box in the Test Operation view, then in the dialog that appears check “Basic authentication”, enter your username (sarbogast as configured in BootStrap.groovy) and password (password), and click OK.

Then hit “Test” again and you should get a response this time:

Now that we know that the connection is working, we will create a basic interface to display the list of Projects. In the screencast, I also show you how to created a basic user interface for the echo service but I’m gonna skip that here.

Head back to IntelliJ and shut down the server. Then right click on grails-app/services and select New>Grails Service:

In the dialog that appears, set the name to org.epseelon.todolist.Todolist. Grails will add the “Service” suffix automatically:

Because I hate to expose my domain model (the way I store data) to the presentation layer (how I present data to the end user), I like to work with Data Transfer Objects to exchange data between presentation and business layers. I want to expose a method to display a list of projects, but instead of returning an array of Project instances, I will create a ProjectListItem DTO class. And since Flash Builder introspection doesn’t like Groovy classes, I will define this DTO class in pure Java. Right-click on src/java, then select New>Java class:

Set org.epseelon.todolist.dto.ProjectListItem as the qualified name for this class, then click OK:

Then modify the code of the ProjectListItem class as the following:

package org.epseelon.todolist.dto;

public class ProjectListItem {
    public Long id;
    public String title;
}

Now you can implement TodolistService:

package org.epseelon.todolist

import org.springframework.flex.remoting.RemotingDestination
import org.springframework.flex.remoting.RemotingInclude
import org.springframework.security.annotation.Secured
import org.epseelon.todolist.dto.ProjectListItem

@RemotingDestination
class TodolistService {

    boolean transactional = true

    @RemotingInclude
    @Secured("ROLE_USER")
    ProjectListItem[] getAllProjects() {
        return Project.findAll().collect {
            new ProjectListItem(
                    id: it.id,
                    title: it.title
            )
        }.toArray(new ProjectListItem[0])
    }
}

Make sure you annotate the method with org.springframework.security.annotation.Secured and not org.codehaus.groovy.grails.plugins.springsecurity.Secured. Now you can start the server in WAR mode again.

NB: At this stage, in the screencast, you have to edit web-app/WEB-INF/flex-servlet.xml in order to uncomment the “context:component-scan” element and configure the base-package attribute. But I just noticed that this part of the flex-servlet.xml configuration file is totally useless since Grails automatically scans annotations in services anyway. So I will remove this from a next version of the plugin. In the meantime, you can simply ignore it.

Now go back to Flash Builder, and in the “Data/Services” view, click the “Connect to Data/Service…” button in the upper right corner:

In the dialog that appears, select BlazeDS and click Next. In the next step, you should now see echoService and our new todolistService. Check only the second checkbox and hit Finish:

Now we have a new entry in our Data/Services view:

Now edit Main.mxml like the following:

<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" 
			   xmlns:s="library://ns.adobe.com/flex/spark" 
			   xmlns:mx="library://ns.adobe.com/flex/mx" 
			   minWidth="955" minHeight="600" 
			   currentState="{channelSet.authenticated ? 'loggedIn' : 'loggedOut'}" 
			   xmlns:services="services.*">
	<fx:Script>
		<![CDATA[
			import mx.controls.Alert;
			import mx.events.FlexEvent;
			
			protected function list_creationCompleteHandler(event:FlexEvent):void
			{
				getAllProjectsResult.token = todolistService.getAllProjects();
			}
			

			protected function loginButton_clickHandler(event:MouseEvent):void
			{
				loginResult.token = channelSet.login(username.text, password.text);
			}

		]]>
	</fx:Script>
	<s:states>
		<s:State name="loggedIn"/>
		<s:State name="loggedOut"/>
	</s:states>
	<fx:Declarations>
		<s:CallResponder id="getAllProjectsResult"/>
		<s:CallResponder id="loginResult" 
						 fault="Alert.show('Could not log you in because ' + event.fault.faultString, 'Login Error')"/>
		<services:TodolistService id="todolistService" 
								  fault="Alert.show(event.fault.faultString + 'n' + event.fault.faultDetail)" 
								  showBusyCursor="true">
			<services:channelSet>
				<s:ChannelSet id="channelSet">
					<s:AMFChannel 
						url="http://localhost:8080/todolist/messagebroker/amf"/>
				</s:ChannelSet>
			</services:channelSet>
		</services:TodolistService>
	</fx:Declarations>
	<s:List id="list" includeIn="loggedIn" 
			x="10" y="10" width="154" height="182"  
			creationComplete="list_creationCompleteHandler(event)" 
			labelField="title">
		<s:AsyncListView list="{getAllProjectsResult.lastResult}"/>
	</s:List>
	<s:Panel includeIn="loggedOut" x="10" y="10" title="Authentication">
		<mx:Form x="0" y="0" width="100%" height="100%">
			<mx:FormItem label="User name">
				<s:TextInput id="username"/>
			</mx:FormItem>
			<mx:FormItem label="Password">
				<s:TextInput id="password" displayAsPassword="true"/>
			</mx:FormItem>
		</mx:Form>
		<s:controlBarContent>
			<s:HGroup width="100%" horizontalAlign="right">
				<s:Button id="loginButton" label="Login"  
						  click="loginButton_clickHandler(event)"/>
			</s:HGroup>
		</s:controlBarContent>
	</s:Panel>
</s:Application>

This code defines 2 states for the application: a loggedIn and a loggedOut state. In loggedOut state we show a login form. In loggedIn state, we show a list of projects. The currentState of the application is bound to the authenticated property of the channelSet because that’s where authentication happens. So when the user clicks on the Login button, channelSet.login() is called. This channelSet is then used by TodolistService when it needs to communicate with the server. When the list is initialized, it calls TodolistService.getAllProjects() and the result is displayed.

For more details on how to create the code above, watch the screencast video.

Before running the application, go to http://localhost:8080/todolist/project/list and create a couple of dummy projects.

When you save and run the application, you see a nice login form:

Enter your username and password and you will see list showing the titles of the projects you have created before.

That’s it for this episode, I think you get my point. Grails BlazeDS plugin makes it very easy to develop a Flex front-end for a Grails back-end, while using all the power of Flash Builder 4. Now there are a couple of limitations, like the fact that we are forced to run the Grails application in WAR mode and the fact that we cannot use Groovy classes as DTO’s. But hopefully I will be able to fix that in the future.

In the meantime, this article will serve as the documentation for Grails BlazeDS plugin. You can download the final version of the todolist application here:

In the next (and last) episode, we’ll talk about creating an iPad client for our todolist application. But I can’t promise I will publish part 3 tomorrow because there’s still some work to be done there.

Enjoy!

18 comments

  1. Thanks for these posts. You got me going with Flex and Grails. I’m quite interested by the upcoming IPhone post too.

    As a relative Flex newby, I have some questions about your design style and perhaps you could help me:

    1. Is there a particular reason you use BlazeDS over GraniteDS? I particularly noted that GraniteDS supports lazy loading, which sounds rather handy.

    2. You write “Because I hate to expose my domain model (the way I store data) to the presentation layer (how I present data to the end user), I like to work with Data Transfer Objects to exchange data between presentation and business layers.” Can you give more explanation in support of this choice? Writing DTOs and copying all your data to them in every service call, like in getAllProjects(), sounds like quite a hassle and very wet (not DRY). What other alternatives are available to us?

    3. What advantages do I gain from using this plugin over using the Grails Flex plugin? Obviously that plugin is unmaintained, but I’m asking from a technical standpoint. The Flex plugin seems pretty easy to use too.

    1. 1. BlazeDS is kind of the “official” way of doing things and it’s supported by Adobe so I consider it more robust. Also, since it is a subset of LiveCycle Data Services, the transition to this very rich framework is much simpler when your application expands and needs more stuff. Finally, in my opinion lazy loading is a bad idea anyway since if you need it, it means you’re exposing your domain model to your presentation layer, which I think is a very bad thing.
      2. There are some necessary hassles. Plus Groovy makes it much easier to transfer this data back and forth. I know there is a Grails DTO plugin but it’s more tailored to use with GWT. And there is the Dozer framework that can make it easier. The way I see it, designing DTO’s is very important as it forces you to sit in the user’s chair.
      3. The Grails Flex plugin is based on Flex 3 and BlazeDS 3, it doesn’t integrate Spring-Flex (which didn’t exist back then) and it makes you put your Flex code (MXML and ActionScript) in your Grails project itself. The latter is not the best way to do it as it makes it very difficult to then import your project into Flash Builder or any other Flex-friendly environment, which is especially critical with all the nice features in Flash Builder 4. Finally, as a Maven “kind of guy” I stick to the “one package per project” mantra: my SWF is a package, it requires its own project.

      Does that answer your questions alright? If not, feel free to ask more.

  2. Thanks, that does answer in that I understand your point of view. However regarding the third point, the Grails Flex plugin does work with Flex 4 and allows you to have your files in a different project in Flash Builder 4 – at least for a simple project, because I did it the other day and it worked. I had a look into Spring-Flex, as an official Spring project it sounds like a great idea to integrate it, but I actually couldn’t see what benefits it gives. Can you tell me what the benefits are?

    I’m looking into GraniteDS. There’s quite an impressive tutorial here which I tried yesterday. http://graniteds.blogspot.com/2009/08/build-flex-crud-application-in-15.html. However it goes against your philosophy of DTOs/”don’t expose domain”. Unfortunately the plugin doesn’t seem to be being maintained anymore, which is definitely a disadvantage against your plugin.

    Good luck with your plugin.

  3. Advantages of Spring-Flex:
    – It’s much easier to configure thanks to namespaces and the Spring way of doing things
    – It integrates seamlessly with Spring Security
    – It has support for asynchronous messaging (http://static.springsource.org/spring-flex/docs/1.0.x/reference/html/ch05.html) which I have not used yet but seems very interesting
    – Plus it just does a lot of things that I don’t have to do on my own like instantiating the message broker and so on.

    I didn’t know that Grails Flex plugin worked with Flex 4, but what is sure is that it integrates BlazeDS 3 and not BlazeDS 4.

  4. Nice series of blogs, looking forward to next part.

    Would you care to comment on the need to keep the DTO objects as java classes as opposed to groovy classes?

    Will this likely change, and do you consider it a problem?

    1. When a groovy class is compiled into bytecode, then decompiled to java source, you can see that groovy compiler adds some sugar to the things you define in order to handle the dynamic aspects. More specifically it adds some static initializers that Flash Builder’s introspection process doesn’t like. Will it change? I don’t know as I have no idea about how to fix that. Do I consider it a problem? Not really given that they are just DTO’s with public fields so there is no big difference in terms of the amount of code you have to type.

  5. Thanks for your posts.

    I did above steps in Grails1.2.2, it works fine. But it seems
    the steps are not suitable to Grails 1.3.3. In Grails 1.3.3, Flex client can’t find any service, including echoService.
    Why? 🙂

    1. I know there is an issue with Grails 1.3 onwards. Unfortunately I’m still trying to figure out why. I will write a post to try to call for help because I’m really stuck on that. Thank you for voicing your support.

  6. thank you for the post. It is great that you don’t even have to configure blazeds and spring to use blazeds. Question: how do you usse blazeds’ jms messaging? How do you configure messaging service? I plan to use activemq as my jms provider. Please advise. Thanks

  7. Is this plugin being worked on/maintained by you? Will is work with 1.3.4 and spring-security-core in the future?

    I also tend to agree with you Sebastien, alot of programmers are exposing their domains (using LifeCycleDS or GraniteDS) to their presentation layer, this is a very very bad idea. Just because LifeCycleDS and GraniteDS do this people should use it beyond throwing a prototype together.

  8. that last sentence should have been….
    Just because LifeCycleDS and GraniteDS do this, people shouldn’t use it beyond throwing a prototype together.

Leave a Reply