Posts Tagged ‘Programming’

Grails Flex Scaffold (GFS)

March 6, 2009

Grails Flex Scaffold (GFS) is a grails’ plugin that deals Flex code generation by scaffolding methodology, including support for presentation and service layers by providing embeded data in your domain classes as original Grails Scaffolding does with Ajax and HTML.

In the first version (GFS v0.1) we attempt to support some basic features in Flex’s CRUD generation staff (Relations, Validations, etc).

Inspired by our experience on Grails we thought it could be a very good idea the fact of adding RIA concept, in order to enhance the user experience.

This plugin DO NOT attempt to get down developers’ skill, instead It tries to make easy repetitive tasks we can find in a project and earn time for critical bussiness items.

In order to explain how this plugin works we are going to write some code for a dummy example app which contains three type of relations (one-to-many, many-to-one and one-to-one) between four domain classes.

Resources:GFSv0.1 plugin – Download

GFS example application – Download

GFS screencast – Download

Prerequisites

  • Grails 1.0.4 (last stable version)
  • Flex 3.0.0 or major

FLEX_HOME and GRAILS_HOME must be defined as environment variable!!

“In this version we should copy FLEX_HOME/ant/lib/flexTasks.jar into GRAILS_HOME/ant/lib”

Off to work!

Domain Model

Domain Model

1 – Grails Project creation

user@cubikalabs:~$ grails create-app gsf-test

2 – Plugin installation (link:download).

user@cubikalabs:~$ cd gfs-testuser@cubikalabs:~/gfs-test $ grails install-plugin [plugin-path]/grails-flex-scaffold-0.1.zip

3 – Generating domain class model

user@cubikalabs:~/gfs-test $ grails create-domain-class customeruser@cubikalabs:~/gfs-test $ grails create-domain-class company

user@cubikalabs:~/gfs-test $ grails create-domain-class phone

user@cubikalabs:~/gfs-test $ grails create-domain-class address

Let’s edit generated domain classes:

Company:

importorg.cubika.labs.scaffolding.annotation.FlexScaffoldProperty//@FlexScaffoldProperty(labelField=”name”) is

//The label field is displayed in edit-view

//of the relation external

@FlexScaffoldProperty(labelField=”name”)

classCompany

{

Stringname

Stringaddress

//One-to-Many

statichasMany = [customers:Customer]

staticmapping =

{

customers lazy:false, cascade:”none”

}

static constraints =

{

name(blank:false)

address(blank:false)

customers(display:false)//Not view customer in Company’s edit-view

}

}

Customer:

classCustomer

{

StringfirstName

StringlastName

Stringemail

DatedateOfBirth

Phonephone

Listaddresses

Companycompany

StringmaritalStatus

Integerage

Booleanenabled

statichasMany = [addresses:Address]

staticbelongsTo = Company

staticmapping =

{

addresses lazy:false, cascade:”all-delete-orphan”

company lazy:false, cascade:”none”

}

static constraints =

{

firstName(minSize:2, blank:false)

lastName(maxSize:20)

dateOfBirth()

age(range:18..99)

email(email:true, blank:false)

//if not declared widget, the default component is a ComboBox

maritalStatus(inList:[“Single”,”Married”,”Divorce”,”Widower”],widget:”autocomplete”)

addresses()

//if inPlace:false, a ComboBox is created in the “edit-view”

//of the class containing it, and it’s filled with the information that makes a

// reference of it.

//Besides, it allows to create a new record from the edit-view of the referenced class

// through a button (“add”)

//by default inPlace is true

company(inPlace:false, nullable:true)

//The componente will be hidden when the form is setted CREATE_VIEW mode

//and sets the defaultValue, in this case the value is true

//If you wish, use the metaConstraint editView:false to hide component in EDIT_VIEW mode

enabled(createView:false,defaultValue:’true’)

}

}

Address:

classAddress{

Stringstreet

Integernumber

Stringzip

Stringobservation

Customercustomer

staticconstraints =

{

street(blank:false)

//if not declared widget, the default

//component is a NumericStepper

number(widget:”textinput”)

zip(blank:false)

observation(widget:”textarea”)

//Not view customer in Address’ edit-view

customer(display:false)

}

}

Phone:

classPhone{

Stringnumber

Stringtype

staticbelongsTo = Customer

staticconstraints =

{

//if not declared widget, the default

//component is a NumericStepper

number(widget:”textinput”)

type(inList:[“Home”,”Movil”])

}

}

4 – Crud Company and Customer Generation

user@cubikalabs:~/gfs-test $ grails generate-all-flex companyuser@cubikalabs:~/gfs-test $ grails generate-all-flex customer

5 – Flex compilation

user@cubikalabs:~/gfs-test $ grails flex-tasks

6 – It’s time to start up our app-server and navigate our application

user@cubikalabs:~/gfs-text $ grails run-app

http://localhost:8080/projectName
Version details

In the first version (GFS v0.1), we put all our efforts in this kind of apps (relations, validations), and we didn’t mind about features as visual component suite and form (via metadata) settings. We have all this staff planned and more planned for future versions (we expect you to contribute your knowledge, questions or whatever you have to contribute).

In nearly future we will have Jira and Confluence apps in order to follow projects releases and bug reporting. On the other hand, we are going to open our SVN for annonimous checkouts, this way everybody will be able to view, modify, use, contribute or whatever you want to do with source code, beta versions,etc.

It is not our porpose to extend this post any more, but it really important for us to mention Marcel Overdijk who developed Grails-Flex-BlazeDS integration.

Success tips (Important information)

Relations

  • many-to-one supports only inPlace:false (this declaration is not required because it’s setted as a default)
  • one-to-many both cases are supported inPlace:false/inPlace:true.
  • one-to-one supports only inPlace:true (this declaration is not required because it’s setted as a default).
  • If relations are declared as inPlace:true, e.g: Customer <-> Address o Customer -> Phone, the included class (Address, Phone) must define the constraint diplay:false for property that is including “custormer(display:false)”. At this moment, this restriction is not valid in generation code time and ends by abort process
  • Relations must ever be lazy:false if not, BlazeDS throws a LazyInitialization exception (in future versions we are going to support this feature with DPHibernate or similar).

Constraints

  • Front-End supported constraints:
    • blank, email, size, minSize, maxSize, min, max, range, url, inList
    • For each Front-End constraint, a Flex validator is generated. This avoids user to persist the entity without the need of Back-End validation.
  • All other constraints (Grails constraints) follows Grails validation way, doing validation on Back-End side which have the responsibility of getting feedback about errors to Front-End. This kind of errors are supported by i18n.
Advertisements