
Grails ships out of the box with adaptive AJAX support.
By default Grails uses the Prototpe library when invoking AJAX request using the Grails remoteLink, formRemote and submitToRemote AJAX tags.
Not only is Grails providing an easy way of integrating AJAX functionality in your pages, but it also allows you to switch to another AJAX library if needed. This is what we mean with adaptive AJAX support.
One of the use cases to switch to another AJAX library is that this library offers more functionality then the default Prototype library. E.g. you want to use the Yahoo! User Interface Library (YUI) within you application for the autocomplete or calendar functionality. In this case you want the YUI library also to be used for your AJAX tags, so you only depend on YUI and not on both YUI and Prototype.
If you want easy support for YUI in your Grails application then just install the Grails Yahoo! UI Library Plugin which I released today. It downloads and installs automatically the latest YUI 2.4.1 2.5.0 distribution in your application, and registers itself to be used with the adapative AJAX tags. It also contains two helper tags to easily include additional YUI javascript and css files as well.
Note that this plugin does not provide any tags for embedding rich ui components without having to deal with javascript libraries. If you are more interested in such a plugin, have a look at the Grails RichUI Plugin. This plugin contains a set of AJAX components not limited to the YUI library.
For a personal application I want to use the YUI autocomplete and calendar functionality so I'm thinking already of a Grails YUI Widgets Plugin which can be installed on top of the YUI Plugin ...
Friday, February 15, 2008
Grails adaptive AJAX support with the Yahoo! UI Library
Tuesday, February 5, 2008
Grails 1.0 released today!

Today the release of Grails 1.0 was announced. See release notes at http://grails.org/1.0+Release+Notes
2008 will be the Grails year!!
Posted by
Marcel Overdijk
at
10:51 AM
0
comments
Wednesday, January 30, 2008
Code by convention with Flex and Spring
Some years ago XML configuration was considered as a great way to configure applications. Take for example Struts' struts-config.xml, in the beginning it was like heaven how you could define all your action mappings etc. But as applications grow it gets harder and harder to maintain this bunch of XML.
The point is applications and application frameworks evolve. In modern application frameworks code by convention is becoming an important feature which reduces repetition and increases uniformity and productivity.
Take for example Grails and Ruby on Rails which are build from the ground up with code by convention in mind. For example in Grails a *Controller.groovy class is a automatically a controller and a *Service.groovy class is automatically a service. You do not need any XML configuration.
Back in my holidays in December I tried Adobe's BlazeDS. From Adobe Labs: BlazeDS is the server-based Java remoting and web messaging technology that enables developers to easily connect to back-end distributed data and push data in real-time to Adobe Flex and Adobe AIR applications for more responsive rich Internet application (RIA) experiences.
What this means is that Flex clients can communicate with Java objects deployed on the server. BlazeDS contains a Java Adapter which forms the infrastructure to make this possible. With Jeff Vroom's Spring Integration you can even use Spring beans to communicate with.
The only drawback with the standard Java Adapter (and so also the Spring Integation) is that each Java object you want to call on the server, you need to configure in remoting-config.xml. Guess what? I don't like that! So what I did is I created a JDK5 annotation to autowire Spring beans directly into BlazeDS. It means when you use Spring and JDK5 you can annotate your service classes with a @RemotingDestination annotation, and they get automatically registered in BlazeDS. Some sort of code by convention I would say!
How it works:
- Download the @RemotingDestination annotation for Spring supporting files at http://www.adobe.com/cfusion/exchange/index.cfm?event=extensionDetail&loc=en_us&extid=1398018. It also includes Jeff Vroom's Spring Factory.
- Expand remotingdestination-annotation.zip
- Copy dist\remotingdestination-annotation.jar in the WEB-INF\lib directory of your web application. Instead you could also include the Java sources (located in src) in your project.
- Download the Spring framework at http://www.springframework.org/download
- Locate spring.jar in the dist directory and copy it in the WEB-INF\lib directory of your web application
- In your Flex services-config.xml configure the SpringAutowiringBootstrapService:
The SpringAutowiringBootstrapService checks all @RemotingDestination annotated classes and registers them within BlazeDS at runtime. It also dynamically creates the Spring Factory.
<?xml version="1.0" encoding="UTF-8"?>
<services-config>
<services>
<service-include file-path="remoting-config.xml" />
<service-include file-path="proxy-config.xml" />
<service-include file-path="messaging-config.xml" />
<service id="spring-autowiring-bootstrap-service" class="flex.contrib.services.SpringAutowiringBootstrapService"/>
<default-channels>
<channel ref="my-amf"/>
</default-channels>
</services>
....
Note that the default channel is required when using runtime registration of remoting destinations.
- Finally annotate your service classes with the @RemotingDestination annotation:
package flex.contrib.samples.mortgage;
import org.springframework.beans.factory.annotation.Autowired;
import flex.contrib.stereotypes.RemotingDestination;
@RemotingDestination(destination="mortgageService")
public class Mortgage {
@Autowired
RateFinder rateFinder;
public void setRateFinder(RateFinder rateFinder) {
this.rateFinder = rateFinder;
}
public double calculate(double amount) {
int term = 360; // 30 years
double rate = rateFinder.findRate();
return (amount*(rate/12)) / (1 - 1 /Math.pow((1 + rate/12), term));
}
}
By default the Spring bean name is used to register the remoting destination. The name can be overridden using the destination attribute of the annotation. The example class uses Spring annotation-based configuration using the @Autowired annotation. In this case the Spring application context would look like:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd">
<context:annotation-config/>
<context:component-scan base-package="flex.contrib.samples"/>
</beans>
That's it! The Mortgage service will be automatically registered without any XML configuration. The @RemotingDestination annotation allows you to easily expose services within BlazeDS. Together with Spring's annotation-based configuration this provides a productive code by convention experience for writing Flex applications with Spring on the server-side.
For more info about the @RemotingDestination annotation, SpringAutowiringBootstrapService see the Javadocs in docs\api.
Posted by
Marcel Overdijk
at
11:30 AM
25
comments
Tuesday, January 29, 2008
BlazeDS Test Drive sample in Grails

In my previous blog entry I introduced the Grails Flex Plugin. I got some reactions on this post and one of them was from Alexander Negoda (aka greendog), who had some problems getting BlazeDS Test Drive Sample 5: Updating data to work on Grails.
A good reason for me to implement the sample myself, and write a small tutorial!
- I assume you have Grails already installed and know the basics. This plugin requires requires the latest and greatest Grails 1.0-final development build. It is not compatible with Grails 1.0-RC4.
- Create a new Grails application by executing
grails create-app productfrom the Grails command line. - From within the
productapplication folder, install the Flex plugin by executing:grails install-plugin flex
All Flex libraries and configuration files will be copied into your application'sweb-appfolder. - Create the
Productdomain class by executing:grails create-domain-class product - Open
Product.groovyand add properties so your domain class looks like:
class Product {
String name
String description
String image
String category
Double price
Integer qtyInStock
} - Create the
Productservice by executing:grails create-service product - Open
ProductService.groovyand change the class so it looks like:
class ProductService {
static expose = ['flex-remoting']
def getProducts() {
return Product.list();
}
def update(Product product) {
def p = Product.get(product.id)
if (p) {
p.properties = product.properties
p.save()
}
}
}
Notice that we expose the service as aflex-remotingservice. - Now we are finished with the domain and service layer and we can focus on the Flex front-end. Within the application's
web-appfolder create a file calledmain.mxmland add the following content:
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" xmlns="*" layout="horizontal"
creationComplete="srv.getProducts()" viewSourceURL="srcview/index.html">
<mx:RemoteObject id="srv" destination="productService"/>
<mx:Panel title="Catalog" width="100%" height="100%">
<mx:DataGrid id="list" dataProvider="{srv.getProducts.lastResult}" width="100%" height="100%"/>
</mx:Panel>
<ProductForm product="{Product(list.selectedItem)}"/>
</mx:Application> - Within the application's
web-appfolder create a file calledProductForm.mxmland add the following content:
<?xml version="1.0" encoding="utf-8"?>
<mx:Panel xmlns:mx="http://www.adobe.com/2006/mxml" xmlns="*"
title="Details" width="100%" height="100%">
<Product id="product"
name="{productName.text}"
category="{category.text}"
price="{Number(price.text)}"
image="{image.text}"
description="{description.text}"/>
<mx:RemoteObject id="srv" destination="productService"/>
<mx:Form width="100%">
<mx:FormItem label="Name">
<mx:TextInput id="productName" text="{product.name}"/>
</mx:FormItem>
<mx:FormItem label="Category">
<mx:TextInput id="category" text="{product.category}"/>
</mx:FormItem>
<mx:FormItem label="Image">
<mx:TextInput id="image" text="{product.image}"/>
</mx:FormItem>
<mx:FormItem label="Price">
<mx:TextInput id="price" text="{product.price}"/>
</mx:FormItem>
<mx:FormItem label="Description" width="100%">
<mx:TextArea id="description" text="{product.description}" width="100%" height="100"/>
</mx:FormItem>
</mx:Form>
<mx:ControlBar>
<mx:Button label="Update" click="srv.update(product);"/>
</mx:ControlBar>
</mx:Panel> - Within the application's
web-appfolder create a file calledProduct.asand add the following content:
package
{
[Bindable]
[RemoteClass(alias="Product")]
public class Product
{
public function Product()
{
}
public var id:int;
public var name:String;
public var description:String;
public var image:String;
public var category:String;
public var price:Number;
public var qtyInStock:int;
}
}
Note that themain.mxml,ProductForm.mxmlandProduct.asfiles are for 99% a copy from the BlazeDS Test Drive sample. Inmain.mxmlandProductForm.mxmlonly thedestination idof theRemoteObjectwas changed. And inProduct.asthealiasof theRemoteClassand the name of theproductIdcolumn was changed. - Before we run the example, let's add some data to the embedded HSQLDB database. In your application's
BootStrap.groovyclass create some records as shown below:
class BootStrap {
def init = { servletContext ->
new Product(name: 'Nokia 6010', category: '6000', image: 'Nokia_6010.gif', price: 99.00, description: 'Easy to use without sacrificing style, the Nokia 6010 phone offers functional voice communication supported by text messaging, multimedia messaging, mobile internet, games and more.', qtyInStock: 21).save()
new Product(name: 'Nokia 3100 Blue', category: '9000', image: 'Nokia_3100_blue.gif', price: 109.00, description: 'Light up the night with a glow-in-the-dark cover - when it is charged with light you can easily find your phone in the dark. When you get a call, the Nokia 3100 phone flashes in tune with your ringing tone. And when you snap on a Nokia Xpress-on gaming cover, you will get luminescent light effects in time to the gaming action.', qtyInStock: 99).save()
new Product(name: 'Nokia 3100 Pink', category: '3000', image: 'Nokia_3100_pink.gif', price: 139.00, description: 'Light up the night with a glow-in-the-dark cover - when it is charged with light you can easily find your phone in the dark. When you get a call, the Nokia 3100 phone flashes in tune with your ringing tone. And when you snap on a Nokia Xpress-on gaming cover, you will get luminescent light effects in time to the gaming action.', qtyInStock: 30).save()
new Product(name: 'Nokia 3120', category: '3000', image: 'Nokia_3120.gif', price: 159.99, description: 'Designed for both business and pleasure, the elegant Nokia 3120 phone offers a pleasing mix of features. Enclosed within its chic, compact body, you will discover the benefits of tri-band compatibility, a color screen, MMS, XHTML browsing, cheerful screensavers, and much more.', qtyInStock: 10).save()
new Product(name: 'Nokia 3220', category: '3000', image: 'Nokia_3220.gif', price: 199.00, description: 'The Nokia 3220 phone is a fresh new cut on some familiar ideas - animate your MMS messages with cute characters, see the music with lights that flash in time with your ringing tone, download wallpapers and screensavers with matching color schemes for the interface.', qtyInStock: 20).save()
new Product(name: 'Nokia 3650', category: '3000', image: 'Nokia_3650.gif', price: 200.00, description: 'Messaging is more personal, versatile and fun with the Nokia 3650 camera phone. Capture experiences as soon as you see them and send the photos you take to you friends and family.', qtyInStock: 11).save()
new Product(name: 'Nokia 6820', category: '6000', image: 'Nokia_6820.gif', price: 299.99, description: 'Messaging just got a whole lot smarter. The Nokia 6820 messaging device puts the tools you need for rich communication - full messaging keyboard, digital camera, mobile email, MMS, SMS, and Instant Messaging - right at your fingertips, in a small, sleek device.', qtyInStock: 8).save()
new Product(name: 'Nokia 6670', category: '6000', image: 'Nokia_6670.gif', price: 319.99, description: 'Classic business tools meet your creative streak in the Nokia 6670 imaging smartphone. It has a Netfront Web browser with PDF support, document viewer applications for email attachments, a direct printing application, and a megapixel still camera that also shoots up to 10 minutes of video.', qtyInStock: 2).save()
new Product(name: 'Nokia 6620', category: '6000', image: 'Nokia_6620.gif', price: 329.99, description: 'Shoot a basket. Shoot a movie. Video phones from Nokia... the perfect way to save and share life\u2019s playful moments. Feel connected.', qtyInStock: 10).save()
new Product(name: 'Nokia 3230 Silver', category: '3000', image: 'Nokia_3230_black.gif', price: 500.00, description: 'Get creative with the Nokia 3230 smartphone. Create your own ringing tones, print your mobile images, play multiplayer games over a wireless Bluetooth connection, and browse HTML and xHTML Web pages. ', qtyInStock: 10).save()
new Product(name: 'Nokia 6680', category: '6000', image: 'Nokia_6680.gif', price: 222.00, description: 'The Nokia 6680 is an imaging smartphone that', qtyInStock: 36).save()
new Product(name: 'Nokia 6630', category: '6000', image: 'Nokia_6630.gif', price: 379.00, description: 'The Nokia 6630 imaging smartphone is a 1.3 megapixel digital imaging device (1.3 megapixel camera sensor, effective resolution 1.23 megapixels for image capture, image size 1280 x 960 pixels).', qtyInStock: 8).save()
new Product(name: 'Nokia 7610 Black', category: '7000', image: 'Nokia_7610_black.gif', price: 450.00, description: 'The Nokia 7610 imaging phone with its sleek, compact design stands out in any crowd. Cut a cleaner profile with a megapixel camera and 4x digital zoom. Quality prints are all the proof you need of your cutting edge savvy.', qtyInStock: 20).save()
new Product(name: 'Nokia 7610 White', category: '7000', image: 'Nokia_7610_white.gif', price: 399.99, description: 'The Nokia 7610 imaging phone with its sleek, compact design stands out in any crowd. Cut a cleaner profile with a megapixel camera and 4x digital zoom. Quality prints are all the proof you need of your cutting edge savvy.', qtyInStock: 7).save()
new Product(name: 'Nokia 6680', category: '6000', image: 'Nokia_6680.gif', price: 219.00, description: 'The Nokia 6680 is an imaging smartphone.', qtyInStock: 15).save()
new Product(name: 'Nokia 9300', category: '9000', image: 'Nokia_9300_close.gif', price: 599.00, description: 'The Nokia 9300 combines popular voice communication features with important productivity applications in one well-appointed device. Now the tools you need to stay in touch and on top of schedules, email, news, and messages are conveniently at your fingertips.', qtyInStock: 26).save()
new Product(name: 'Nokia 9500', category: '9000', image: 'Nokia_9500_close.gif', price: 799.99, description: 'Fast data connectivity with Wireless LAN. Browse the Internet in full color, on a wide, easy-to-view screen. Work with office documents not just email with attachments and memos, but presentations and databases too.', qtyInStock: 54).save()
new Product(name: 'Nokia N90', category: '9000', image: 'Nokia_N90.gif', price: 499.00, description: 'Twist and shoot. It is a pro-photo taker. A personal video-maker. Complete with Carl Zeiss Optics for crisp, bright images you can view, edit, print and share. Meet the Nokia N90.', qtyInStock: 12).save()
}
def destroy = {
}
} - Now run the application by executing
grails run-appand when started open a browser and navigate tohttp://localhost:8080/product/main.mxml

Now enjoy and look at the list of products retrieved during startup of the application. Navigate trough the product list and change the properties on the right side. Pushing the Update button will update the record in the database.
Note that updating causes a long stacktrace in the console window, but the update succeeds anyway. It's a StackOverflowError within HSQLDB; I tested the code on a MySQL database and then there is no error thrown.
Sunday, January 20, 2008
Flex on Grails: Introducing the Grails Flex plugin

I haven't touched this blog for the past months as life has been very busy since my son was born. But now it's time again, as I released the Grails Flex Plugin today.
With the plugin Grails services can be exposed as RPC remoting destinations within BlazeDS - Adobe's server-based Java remoting and messaging technology. These remoting destinations can be used in Flex rich internet applications to communicate with the server to restrieve or send data.
Great thing is you can use all nice features from Grails like reloading, GORM etc. and have a real RIA application on the front-end.
See Grails Flex Plugin for more information and a simple usage example.
Posted by
Marcel Overdijk
at
6:51 AM
24
comments
Saturday, October 27, 2007
Amazing JetGroovy plugin

First of all I need to say that I'm a happy daily Eclipse user; Eclipse does (almost) everything I want from a Java IDE.
In the past I also used JDeveloper using Oracle's proprietary Application Development Framework (ADF) and experimented a little bit with NetBeans.
But I actually never tried IntelliJ. Maybe because the price tag of $499 and because Eclipse is working good enough for FREE.
IntelliJ IDEA 7.0 was released recently and the fully functional Beta version of the JetGroovy plugin provides excellent Groovy and Grails support.
A lot of people were very enthusiastic about this JetGroovy plugin I gave it a try this evening and I was really amazed as it worked perfectly:
Code completion/assistance
- Groovy code completion for keywords, classes, fields and methods
- Cross-resolution between Groovy and Java classes, methods and fields
- Syntax and error highlighting
- Groovy-aware refactoring
Grails application and artifact creation
- Grails applications can be created from using a wizard
- Grails artifacts (like domain classes, controllers, views etc.) can be created using a wizard
GSP support
- Groovy code completion
- Tag completion (both Grails core and custom created tags; even tags with custom namespaces are resolved ;-) !)
When developing Groovy and/or Grails projects then IntelliJ is a real recommendation.
I hope one day we will see the same functionality provided by the Groovy Eclipse plugin.
Posted by
Marcel Overdijk
at
1:09 PM
2
comments
Wednesday, October 10, 2007
Some great Groovy/Grails news this week

Some really good Groovy and Grails news this week I wanted to mention (or better copy from Graeme Rocher's Blog)
First LinkedIn, a online network of more than 14 million experienced professionals from around the world, are looking for software engineers preferably with Groovy/Grails experience.
Then big ERP software giant SAP announced that they have released a new community driven product called Composition on Rails that allows you to use their SAP NetWeaver Composition Environment to quickly prototype applications using Groovy/Grails.
And today G2One Inc - the Groovy/Grails company was announced. G2One has been founded by Graeme Rocher (Grails Project Lead), Guillaume LaForge (Groovy Project Lead) and Alex Tkachman (Former JetBrains COO) to provide consultancy, training, support and products around Groovy & Grails. Personally I think offering commercial support etc. will help adoption signifantly. And with this Groovy/Grails can be developed further. This is the same as e.g. JBoss and Spring are offering great open source software for free, but still making money to constantly evolve this free software.
Posted by
Marcel Overdijk
at
3:48 AM
0
comments
