Last updated by wal5hy 4 years ago

GraniteDS Flex Plugin

This plugin provides integration between Grails and Adobe Flex using Granite Data Services

GraniteDS

GraniteDS is an open source project that provides integration between Adobe Flex and Java frameworks. It has had full support Hibernate and Spring for a long time, so implementing the integration with Grails is quite natural. The plugin is currently a beta version and has been tested with Grails 1.1.

Features

  • Automatic configuration: the various parts required in web.xml and other Flex/GraniteDS configuration files are automatically setup by the plugin. GraniteDS 2.0 beta 1 Java and Flex libraries are included.
  • Automatic generation of the Flex domain classes: the embedded Gas3 generator automatically generates as3 classes from the Groovy model. It is required though to use JPA annotations for the Groovy entities. Gas3 is registed as a compilation event listener, so there is no manual operation needed in most cases.
  • On-the-fly Flex compilation with the GraniteDS Web compiler: trying to access someUrl.swf will trigger the compilation of a someUrl.mxml file from the grails-app/views folder.
  • Includes the GraniteDS Tide client framework: it gives full support for transparent lazy loading of collections, paged data and other data related features.
  • Grails services and controllers can be exposed as Flex remoting destinations with a simple annotation: no particular configuration is needed to expose a Grails component to Flex, just use the org.granite.tide.annotations.TideEnabled. Newly deployed or redeployed services are automatically exposed without any manual operation.
  • Grails controllers results can be used with Flex data binding: the model variables returned by controller components are available as Tide context variables and can easily be bound to the Flex UI.

Installation

Use this from the project folder:

grails install-plugin gdsflex

Warning: in some cases, there can be a compilation problem after having installed the plugin with 'Gas3 class not found. If you encounter this, just type this once:

grails gas3

Flex compilation

The GDS plugin embeds the Flex OEM compiler to automatically compile mxml files present in the grails-app/views folder. For example, requesting http://localhost:8080/myApp/myApp.swf will look for an existing swf in grails-app/views/swf/myApp.swf. When it does not exist, it tries to compile a myApp.mxml found in grails-app/views. ActionScript classes for the domain model are generated in grails-app/views from the Groovy domain classes. When using Flex Builder, you can setup grails-app/views as a Flex source folder and build the swf in grails-app/views/swf.

Exposing Grails services

Exposing a Grails service as a Flex destination just require adding the org.granite.tide.annotations.TideEnabled annotation to the service:

@Entity
class Person {

@Id @GeneratedValue Long id;

@Version Integer version

@Basic String firstName

@Basic String lastName }

@TideEnabled class PeopleService {

def list() { return Person.list() } }

Using the service from Flex can be done using the Tide client API:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
    preinitialize="Spring.getInstance().initApplication()">
    <mx:Script>
        import org.granite.tide.spring.*;
        import mx.collections.ArrayCollection;
        import org.granite.tide.events.TideResultEvent;

private var tideContext:Context = Spring.getInstance().getSpringContext();

private function listPeople():void { tideContext.peopleService.list(listResult); }

private function listResult(event:TideResultEvent):void { people = event.result as ArrayCollection; }

[Bindable] private var people:ArrayCollection = new ArrayCollection(); </mx:Script>

<mx:Button label="List people" click="listPeople()"/> <mx:DataGrid dataProvider="{people}"> <mx:columns> <mx:DataGridColumn dataField="firstName"/> <mx:DataGridColumn dataField="lastName"/> </mx:columns> </mx:DataGrid>

</mx:Application>

There are 3 important things here :

  • the preinitialize handler is used to register the application with the Tide framework
  • the Tide context allows to get client proxies to server components
  • tideContext.peopleService gets a client proxy to the PeopleService Grails service
The Tide framework can also inject references to client proxies in Flex components:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
    preinitialize="Spring.getInstance().initApplication()">
    <mx:Script>
        import org.granite.tide.spring.*;
        import mx.collections.ArrayCollection;
        import org.granite.tide.events.TideResultEvent;

[In] public var peopleService:Object;

private function listPeople():void { peopleService.list(listResult); }

private function listResult(event:TideResultEvent):void { hello = event.result as ArrayCollection; }

[Bindable] private var hello:ArrayCollection = new ArrayCollection(); </mx:Script>

<mx:Button label="List people" click="listPeople()"/> <mx:DataGrid dataProvider="{people}"> <mx:columns> <mx:DataGridColumn dataField="firstName"/> <mx:DataGridColumn dataField="lastName"/> </mx:columns> </mx:DataGrid>

</mx:Application>

One important thing when using the Tide framework is that the entities keep managed on the Flex client and can be considered as real JPA detached entities. Entities received as arguments for a service can be directly saved or updated with the GORM extra persistence methods save, update and delete.

Exposing Grails controllers

Grails controllers can also be exposed with the TideEnabled annotation. The model variables received from controller method are directly bound to the Tide context as context variables.

@TideEnabled
class PeopleController {

List people

def list = { people = Person.list() } }

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
    preinitialize="Spring.getInstance().initApplication()">
    <mx:Script>
        import org.granite.tide.spring.*;
        import mx.collections.ArrayCollection;

[In] public var peopleController:Object;

[Bindable] [In] public var people:ArrayCollection = new ArrayCollection(); </mx:Script>

<mx:Button label="List people" click="peopleController.list()"/> <mx:DataGrid dataProvider="{people}"> <mx:columns> <mx:DataGridColumn dataField="firstName"/> <mx:DataGridColumn dataField="lastName"/> </mx:columns> </mx:DataGrid>

</mx:Application>

You can also transmit request parameters from the Flex client, they will be available in the controller params map.

@TideEnabled
class PeopleController {

List people

def list = { people = Person.findByName(params.searchString) } }

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
    preinitialize="Spring.getInstance().initApplication()">
    <mx:Script>
        import org.granite.tide.spring.*;
        import mx.collections.ArrayCollection;

[In] public var peopleController:Object;

[Bindable] [In] public var people:ArrayCollection = new ArrayCollection(); </mx:Script>

<mx:TextInput id="tiSearch"/> <mx:Button label="List people" click="peopleController.list({searchString: tiSearch.text})"/> <mx:DataGrid dataProvider="{people}"> <mx:columns> <mx:DataGridColumn dataField="firstName"/> <mx:DataGridColumn dataField="lastName"/> </mx:columns> </mx:DataGrid>

</mx:Application>

Choosing between using services and controllers is a matter of preference and application design. Using services requires a little more work on the client side, using controllers simplify the integration but imply stronger coupling between the Flex view and the Grails controller.

More details and documentation on the use of the GraniteDS Tide framework for Spring can be found on the GDS site at http://www.graniteds.org/confluence/display/DOC20/6.+Tide+Data+Framework.

Plugin history

0.1 (16/03/2008)

  • Initial release