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.
- 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”
Domain Model
1 – Grails Project creation
2 – Plugin installation (link:download).
3 – Generating domain class model
user@cubikalabs:~/gfs-test $ grails create-domain-class phone
user@cubikalabs:~/gfs-test $ grails create-domain-class address
Company:
//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:
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:
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
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.
Tags: development, Flex, Grails, Groovy, Programming
March 16, 2009 at 12:24 pm |
Wow this looks pretty awesome. You planning on publishing it to the Grails central plugin repository?
March 16, 2009 at 12:50 pm |
Hi, I’m Gonzalo Clavell from Cubika Labs, first of all thank you very much for your comment, it is very important for us .
We are expecting for Grails central answer, while developing some other features as Reporting, I18n, and scripts improvements.
This improvements will be integrated in next version GFSv0.2, which is coming soon.
I hope you could enjoy this plugin, whatever support you need post your doubts, we will be answering as soon as posible.
Regards,
Gonzalo
March 18, 2009 at 1:52 pm
Your account has been approved.
March 18, 2009 at 7:04 pm
Graeme Rocher:
Thank you very much for your support.
Next week we will move all GFS’s staff to codehaus (wiki,svn,jira,etc).
We hope you follow helping us as you do normally.
March 16, 2009 at 4:06 pm |
When are you going to release this plugin for grails-1.1?
March 16, 2009 at 5:07 pm |
There are some error’s in your current version.
1. Setting FLEX_HOME to “D:\Program Files\Adobe\Flex Builder 3\sdks\3.2.0” doesn’t work. (OS: Window XP Professional)
2. Maybe it will be better if flex_src will generate under “${basedir}/src/flex” and maybe flex_lib under “${basedir}/lib/flex” (like gwt-plugin does)
3. IMHO configure files under “${basedir}/conf/flex”.
4. In my project I use mx:ModuleLoader. In Flex builder Modules compiled automatic. Is it possible to add this behaviour in your plugin?
You did a great work!!! I’m waiting for release under grails 1.1.
Sorry for English.
March 16, 2009 at 7:13 pm |
Hi, thanks for your post!
Here are the answers for your questions
1 – It’s strange. Make sure you changed the file on $(basedir)/flex.properties and not $(flexScaffoldBaseDir)/src/ flex/flex.properties. Obviously, we are going to take a look at this point.
2 – We understand your point of view, but we decided to copy the Adobe’s configurations for projects “Flex/j2ee”.
We omitted to mention in this post something really important, Grails’ project can be import into eclipse and it will take (when run for the first time the flex-generate-all this generates the files .flexProperties and .actionScriptProperties) the “Flex Nature”
3 – the same as for point 2, but we can organize it in “$(basedir)/config/flex”
4 – Have in mind to support modules, not for version 0.2 but certainly in nexts.
We have planned to be testing GFSv0.1 on Grails-1.1 the next week, as soon as posible we will upload tested version.
March 17, 2009 at 9:30 pm |
Sorry, also we ommited to tell you in the last comment that to run the script “flex-tasks” you should copy FLEX_HOME/ant/lib/flexTask.jar into GRAILS_HOME/ant/lib
We updated the post explaining it.
Regards,
Ezequiel
March 18, 2009 at 7:14 am |
Thank you for your support.
About this question
>>Setting FLEX_HOME to “D:\Program Files\Adobe\Flex Builder 3\sdks\3.2.0″ doesn’t work. (OS: Window XP Professional)
It was my mistake. The path must be:
FLEX_HOME = “D:/Program Files/Adobe/Flex Builder 3/sdks/3.2.0”
March 18, 2009 at 10:14 am |
One more thing about $(flexScaffoldBaseDir)/scripts/FlexTasks.groovy
May be it’ll be better to change ${grailsHome} to ${flexHome}
You current version (string number 22,23) file: $(flexScaffoldBaseDir)/scripts/FlexTasks.groovy:
Ant.taskdef (name:’mxmlc’, classname:’flex.ant.MxmlcTask’, classpath:”${grailsHome}/ant/lib/flexTasks.jar”)
Ant.taskdef (name:’gspWrapper’, classname:’flex.ant.HtmlWrapperTask’, classpath:”${grailsHome}/ant/lib/flexTasks.jar”)
My version:
ant.taskdef(name:’mxmlc’, classname: ‘flex.ant.MxmlcTask’, classpath: “${flexHome}/ant/lib/flexTasks.jar”)
ant.taskdef(name:’gspWrapper’, classname: ‘flex.ant.HtmlWrapperTask’, classpath: “${flexHome}/ant/lib/flexTasks.jar”)
March 18, 2009 at 12:15 pm |
Thanks for your improvement.
We fixed it for the next version and also removed the configuration of FLEX_HOME on flex.properties to avoid this errors.
March 18, 2009 at 4:28 pm |
It’s me again.
$(flexScaffoldBaseDir)/scripts/FlexTasks.groovy
string 73:
target(compile:’Compile Flex project into SWF file’)
{
depends(clean)
….
I suppose depends(clean) is useless in this line.
Because Adobe say that FlexTask can determinate dependences and it is smart enough to decide the needs to recompile the swf (compiler create main.swf.cache).
Maybe this features available in last version (I have 3.2.0)
Here it is what I get in my console:
>grails flex-tasks compile
Welcome to Grails 1.1 – http://grails.org/
Licensed under Apache Standard License 2.0
Grails home is set to: C:\Program Files\Grails
Base Directory: D:\project
Running script D:\project\.\plugins\flex-scaffold-0.1\scripts\FlexTasks.groovy
Loading configuration file D:\Program Files\Adobe\Flex Builder 3\sdks\3.2.0\frameworks\flex-config.xml
Recompile: D:\project\flex\src\view\LoginScreen.mxml
Reason: The source file or one of the included files has been updated.
Recompile: D:\project\flex\src\Main.mxml
Reason: The source file or one of the included files has been updated.
Files changed: 2 Files affected: 0
D:\project\web-app\main.swf (759458 bytes)
Flex compile Done!
March 18, 2009 at 5:01 pm |
Thanks, we’ll remove that line
March 18, 2009 at 8:56 pm |
Just what I have been looking for!
This is a hugely significant initiative. I can’t help feeling that HTML/Javascript are “old hat” and that we must break away from the limitations imposed on us by web 1.0 and the challenges of code running and being rendered on many different browsers. The AVM (FlashPlayer) supporting Flex/Flash/AS seems a natural solution to this – just as Java/JVM was a natural solution to C/C++ and the issues of compiled code not running on different CPUs.
Do you have any ideas when a version that runs under Grails 1.1 will be ready?
I wish you every success with this.
Great work guys!
March 18, 2009 at 9:14 pm |
Thanks for you comment, next week we plan to begin tests with Grails-1.1 and published as soon as possible
March 18, 2009 at 9:17 pm |
Excellent. I look forward to trying it out…
March 19, 2009 at 6:10 pm |
Congratulation!!!
I found this plugins on grails.org.
The “Cairngorm Deepdive” presentation says that developer have to use cairngorm ServiceLocator because:
“… It also handles security credentials for the services …”
IMHO it’ll be good features to connect your plugin with “Spring Security plugin”. Or give a tutorial how they can be connected together.
Sorry for bed English.
March 19, 2009 at 8:11 pm |
Hi Anatoliy, yesterday we published!!!. We’re preparing everything to migrate to codehaus (source, documentation, examples, screencast).
Regarding your question about ServiceLocator, although we believe that Cairngorn is the best framewrok to develop Flex applications, we found it difficult to declare each service via MXML. That’s why we chose a “static private var _service” in each concret BusinesDelegate. Anyway we’re planning to extend the ServiceLocator (tied to the priority: we’ll analyze in which version will be it) and register the services in runtime such as the events/commands in the FrontController.
The RemoteObject has the methods of “setCredentials()” and “logout()” which allow us to generate the same functionality that the ServiceLocator. We could wrap these methods in the BusinessDelegate.
Security is also a task pending and we have thought to realice the integration as soon as we established the plugin (users, roles and permissions).
With more time we’ll do a howto of Flex integration with Acegi.
Next week we’re going to have the Jira Project available so we all could vote the features we would release in future versions and the functionalities that are essential for the plugin to be useful.
We hope you could join us with your participation.
Regards,
Ezequiel
March 23, 2009 at 9:22 am
Thank you for your invitation.
I’d like to join to this project.
Unfortunate I can’t do it right now. I have a project, it must be done at the end of march. As soon as I finish it, I’m yours 🙂
March 24, 2009 at 12:55 pm |
The first is:
Adobe’s published “AdvancED Flex 3 excerpt: Integrating via data and media services”. You can download for free. I think this information can be very usefully for you. It describe the architecture of BlazeDS with examples.
The second:
I have a question. I use some codes from your plugin in my project.
Do you do something special for casting from Object to ValueObject?
I can’t force to working type casting.
Generated code from yours plugin:
new CustomerCRUDEvent(CustomerCRUDEvent.SELECT_EVENT,dg.selectedItem as CustomerVO).dispatch()
I mean “dg.selectedItem as CustomerVO”
I have similar code and I always get this error :(:
TypeError: Error #1034: Type Coercion failed: cannot convert Object@1102a6f1 to
March 24, 2009 at 2:17 pm |
Hi Anatoly, Thanks for the link, I’ll read
With regard to cast, we do nothing special
We always work with specific types of objects such as: Customer, Address, etc.
Flex does not allow cast objects to concret objects, it will always throw this error at runtime.
We always fill the dataProvider with concrete objects (the DataGrid always shows a list of concret object) that is why it works.
Check whether the objects that you have in the DataGrid are the data type that you want cast.
If you fill dataProvider with a service, check if your Remote Class is not well configured, check [RemoteClass(alias=’…..’)]
Regards,
Ezequiel
April 28, 2009 at 3:33 pm |
I find out why it’s some time happen.
Flex compile have optimization if you import some class but don’t use it by default it remove it.
And in debug session under FlexBuilder if you return array list from grails.
Array will be the array of object.
To remove it you have to include dummy variable like:
private var dummyPerson:PersonVO;
I hope this information can help someone to safe his time
March 25, 2009 at 12:34 pm |
Thank you for your soon answer.
I get what you mean. I think you right.
How do you do this?
I mean the algorithm which cast remote ArrayCollection to specific types.
I suppose the algorithm hides from me in com.cubika.labs.pagination.PageFilter.
Is it possible to view it (of course if this code is open source)?
March 25, 2009 at 5:32 pm |
Hi Anatoliy, us do nothing, the whole algorithm to convert the objects makes BlazeDS.
PageFilter just paging logic.
if you got a RemoteObject with the following method:
def getCustomers()
{
Customer.list()
}
BlazeDS will transform your Customer List in an ArrayCollection of CustomerVO only if your VO (CustomerVO) has the metadata RemoteClass(alias =”…”) correctly defined.
Obviously, the request must be via BlazeDS.
In the gfs-test are the services we use to perform CRUD
grails-app/services/CustomerService.groovy and
grails-app/services/CompanyService.groovy can you notice that there’s a method called list() that filled the combo of many-to-one inPlace:false
The command is flex_src /command/company/ListComanyCommand.as
Anything, send me an e-mail with the error code and I can help you to resolve it
March 26, 2009 at 6:36 am
I’m sorry for bothering you.
I found what was wrong in my code.
In my project I develop a grid in flex (similar features EXTJS). I’m going to give it to you team as soon as I finish it. I think you can adapt it in you architecture.
March 26, 2009 at 12:02 pm
Anatoliy, good for you. We hope your component
March 26, 2009 at 12:19 pm |
It’s just like idea.
I use Flex Builder (Eclipse) and often use shortcut CTRL+SHIFT+R for searching needed class.
What we have now:
{flex_src}/model/customer/CustomerModel.as
{flex_src}/service/customer/CustomerBusinessDelegate.as
{flex_src}/model/customer/CustomerModel.as
{flex_src}/event/customer/CustomerCRUDEvent.as
They are all begin from “Customer”. And now we are lookin on commands class. They aren’t start with “Customer”
{flex_src}/event/customer/
CreateCustomerCommand.as
DeleteCustomerCommand.as
GetPaginationListCustomerCommand.as
ListCustomerCommand.as
SaveOrUpdateCustomerCommand.as
SelectCustomerCommand.as
IMHO it’ll be better for agile developing to rename this class:
CustomerCreateCommand.as
CustomerDeleteCommand.as
CustomerGetPaginationListCommand.as
CustomerListCommand.as
CustomerSaveOrUpdateCommand.as
CustomerSelectCommand.as
What do you think about this?
March 26, 2009 at 12:35 pm |
Yes, it’s a good point, we’ll refactor
March 26, 2009 at 5:32 pm |
Hi | Hola
What about the 0.2 version or the SVN repo?. I have tried the 0.1 version and found a couple of glitches but overall it has been an impressive experience. ¡Enhorabuena!.
Eduardo.
March 26, 2009 at 7:02 pm |
Hi thanks for your comment.
Tomorow we release GFSv0.1.1 for Grails 1.1 support and some bugs were fixed.
Next week we’re going to publish all code into codehaus svn, docs, and jira. Last one will carry with the responsibility of containing future releases plan where you can see releases state. So you can report your “glitches” as bugs too.
Regards
March 31, 2009 at 2:04 am |
Hello! I’m Brazilian. How to display new Date() in forms? I just like put new Date() in field timestamp ( Postgresql 8.3 ).
Thanks!
Sucess!
March 31, 2009 at 2:34 am |
Hello, I do not understand your question.
Maybe I it can help.
At the moment GFS doesn’t support timestamp to generate code.
If you want to use a property of the type timestamp so you can do the following:
Set DomanClass’ property like Date and then run generate-all-flex you may modify a timestamp.
GFS will generate the DateField in your form and you will have no problem using the timestamp via BlazeDS.
We are planning to support it in the next version.
Regards.
March 31, 2009 at 2:40 am |
Thank you Ezekiel! I understand. Another question, how can I hide some classes? I have many tables and would like some auxiliaries were charged only on relationships.
The work of you is amazing. I would like to contribute, I do not have much, but I would like to contribute in some way. How could I make a donation to the project?
Again, thank you! And success.
March 31, 2009 at 3:10 am |
GFS only generate CRUD for class that you put in “generate-all-flex”.
GFS not support generate all DomainClass (at the moment).
If you need to hide a DomainClass inside a relationship you must be set display:false into property’s constraint.
For example:
class Company
{
Customer customer
static constraints = {
customer(display:false)
}
}
//Customer is not going to be visible in Company’s form
You can contribute with us using GFS and to report the issues that you find and also the improvements we should develop to have a useful plugin.
We expect to see your application working.
You can see documentation of the plugin in:
http://docs.codehaus.org/display/GFS
Also you can visit the plugin in the page of grails:
http://grails.org/plugin/flex-scaffold
Any doubt that you have does not hesitate to ask us
Thank you very much.
March 31, 2009 at 3:07 am |
Ok! With respect to the classes, I changed the. /Flex_src/Main.mxml and gave everything right, perfect!
March 31, 2009 at 3:09 am |
I am really impressed … I’m not really a programmer, and so little knew the groovy or grails, but with only 2 days could develop a good system with many relationships, with the help of GFS plugin. Fantastic!
March 31, 2009 at 3:47 am |
Ok! You could tell me where I could change to get the timestamp?
March 31, 2009 at 4:14 am |
in your domainClass
class aClass
{
Date time
}
run
grails generate-all-flex
edit your Class
class aClass
{
Timestamp time
}
run
grails flex-tasks
grails run-app
if this is not what you need, you could explain to me more about what you want to do?
Regards
March 31, 2009 at 4:21 am |
Ok! I need to get the system date as default in my field. Or even the pattern of groovy.
Thank you!
March 31, 2009 at 12:22 pm |
Ok. you need date format.
In flex you can use a DateFormatter
http://www.igorcosta.com/flex3/doc/mx/formatters/DateFormatter.html
and in groovy a Date.format()
http://groovy.codehaus.org/JN0545-Dates
Regards
April 2, 2009 at 2:33 pm |
List of Values – LOV
Hello! Friend, Is possible use the JSON and JQUERY to assemble a list of values, return to the fields?
April 7, 2009 at 10:14 pm |
This is great!
Is there a plan to support the scaffolding for custom validation?
For example: defining grails’ custom validator with backend validation logic and have GFS generates the Flex view with that custom validator?
Thanks
April 8, 2009 at 12:21 am |
Hi, thanks for your comment.
We’re planning to support custom validation but not in the next version. Probably it’ll be on version 0.3.
GFSv0.2 will be release this week, we haven’t plan the date of GFSv0.3 release.
The time that take us to update each version is 20 days more or less.
Regards,
Ezequiel
April 14, 2009 at 9:30 pm |
Hi guys,
congratulations! Good job.
I’m just reporting a strange behavior in the example. After created a customer I double clicked on the same customer and update it marital status. When I selected the same customer the phone is missing.
April 17, 2009 at 12:05 am |
Hi,
I could not reproduce this error.
On the other hand, we have a bug when we try to update the relations one-to-one that even we could not solve
Regards
April 15, 2009 at 9:10 am |
How difficult would it be to make this work with domain classes defined in Java under grails-app/src/. Grails generate-all works for hibernate-mapped classes. Would anyone be able to point me in the right direction on how I can modify this? Thanks.
April 16, 2009 at 11:55 pm |
Hello,
GFS does not support hibernate-mapping.
At the moment we are not going to focus our efforts on that.
You can start watching GenerateAll also I’m not sure that everything works as it works with Grails Domain classes (Thinking about the metacosntraint).
Perhaps you can create a script that transform your Java’s classes to Groovy, then you run “generate-all-flex” and then you use it in your java configuration (just you create Groovy’s model to generate the Scaffold)
Regards
June 9, 2009 at 2:44 am |
great work. Thanks for sharing.
October 12, 2009 at 8:30 pm |
Hello Ezequiel, Development on GFS has stoped?
October 13, 2009 at 5:58 pm |
Hi Israel, gfs is in development status, I hope a new release in early november.
Regards
June 19, 2010 at 12:41 pm |
wow, awesome post, I was wondering the same thing. and found your site by yahoo, learned a lot, now i’m a bit clear. I’ve bookmark your site and also add rss. keep us updated.
August 22, 2010 at 11:58 pm |
Looks pretty cool, though I got a NPE (Cannot get property ‘starksecurity’ on null) when I ran the example.
Is this project dead now?
August 23, 2010 at 11:34 am |
Hi, we’re working on new version, but we’re having some delays. We expect to have some release soon.
Regarding your comment, to solve this you need run “grails stark-security-install-full”
This post explain how it work.
Regards,
Ezequiel