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.

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.

Thursday, October 4, 2007

Grails i18n templates plugin released



After my previous post about i18n aware scaffolding templates I decided to create a plugin for those templates. For documentation and installation instructions see http://www.grails.org/I18n+Templates+Plugin

Tuesday, September 25, 2007

Grails scaffolding templates improved; i18n aware templates available for download



Despite the fact that the Grails scaffolding templates can be customized, it has always bothered me that the "editors" in the create and edit views were fixed. This meant that tr, td and input elements could not be customized. In the current RC1 development snapshot the fixed code has been moved to a new template which can be customized when installing the templates.
[Note that the templates are still limited to list, create, edit and show views]

You can now customize the way various editors should be rendered, or maybe you want a complete different editor as used in the default templates. E.g. use the fancy Yahoo! UI Calendar instead of the default Grails datePicker.

Or use fully i18n aware templates which can be downloaded here. The i18n templates are now available by a new plugin: http://www.grails.org/I18n+Templates+Plugin. To use them, install the default templates in your project by running grails install-templates. This should create a folder \src\templates\scaffolding containing the default templates. Copy the downloaded templates in this folder and Grails will use them to generate a i18n aware application.

Here are some guidelines for resolving the i18n labels and messages for your domain classes. Imagine you application consists of these 2 domain classes:


class Author {
static hasMany = [books:Book]
String name

static constraints = {
name(blank: false, maxSize: 50)
}
}

class Book {
Author author
String isbn
String title
String category
Float price
String description

static constraints = {
author()
isbn(blank: false, maxSize: 10)
title(blank: false, maxSize: 50)
category(inList: ["Fantasy", "Mystery", "Romance", "Thriller"])
price(min: 0F, max: 100F, nullable: true)
description(blank: true, maxSize: 500)
}
}


Then by default the application is generated using the labels and messages as normal.
But you can change them by adding the following entries to your messages.properties:

# General messages
home=Home
list=List
new=New
create=Create
edit=Edit
update=Update
delete=Delete
delete.confirm=Are you sure?

# Author messages
author=Author
author.plural=Authors
author.created=Author {0} created
author.updated=Author {0} updated
author.deleted=Author {0} deleted
author.not.found=Author not found with ID {0}
author.id=ID
author.books=Books
author.name=Name

# Book messages
book=Book
book.plural=Books
book.created=Book {0} created
book.updated=Book {0} updated
book.deleted=Book {0} deleted
book.not.found=Book not found with ID {0}
book.id=ID
book.author=Author
book.isbn=ISBN
book.title=Title
book.category=Category
book.category.Fantasy=Fantasy
book.category.Mystery=Mystery
book.category.Romance=Romance
book.category.Thriller=Thriller
book.price=Price
book.description=Description

Off cource these English messages would not change anything, as the values would also be used as default. But you can now translate your complete application by just adding resource bundles for that language, and translating the properties.

Note that also the list constraint (by domain.property.value) is displaying i18n labels!

If I have time this week I might create a standalone plugin with these templates. This would include the general labels already then, and maybe some other useful features.

My end goal (and I'm thinking of this since I learned about Grails) is to have a 4GL-like application generator which uses it's own DSL to generate a Grails application. Think of defining number of rows to display in list, is insert allowed, is update allowed, etc.

Wednesday, September 12, 2007

Sten is born



Today I became a proud dad of my first child. His name is Sten!

Monday, September 3, 2007

Grails 1.0 on the horizon



Last week Grails 0.6 was released and the 1.0 release is coming closer every day now!

The 0.6 release contained the following key features:


  • Joint Groovy/Java Compilation

  • Spring Web Flow Integration

  • Support for Spring scopes to allow scoped services

  • Improved support for REST with automatic XML/JSON marshalling and RESTful URL mappings

  • New Config DSL for configuration not possible by convention

  • Refreshed scaffolding interface and branding

  • Support for Sitemesh inline decorators

  • Controllers can now call tag libraries as methods

  • New GSP tags

  • Massive improvements to speed of start-up time, unit tests and generation tools



Besides the great Spring Web Flow integration, and out-of-the-box support for rendering XML and JSON responses (formerly known as the Converters plugin), also the scaffolding views were revamped. Scaffolding now provides a professional and good looking user interface. Take a look below!

Wednesday, August 1, 2007

Another Sexy Flex Grails Example



Here is another (quick) Flex example which uses Grails on the back-end. It contains all CRUD operations in just one screen. Just follow the steps below to see it for yourself:


  1. Create a new grails application: grails create-app flexongrails

  2. Create a new Book domain class: grails create-domain-class Book
    Open the Book domain class and replace the code with:
    class Book { 
    String isbn
    String title
    String author
    Float price
    String format

    static constraints = {
    isbn(maxLength:20, unique:true)
    title(maxLength:50)
    author(maxLength:50)
    price(min:0F, max:999F, scale:2)
    format(inList:["Hardcover", "Paperback", "e-Book"])
    }
    }

  3. Create a new Book controller: grails create-controller Book
    Open the Book controller class and replace the code with:
    class BookController {

    def index = { redirect(action:list, params:params) }

    // the delete, save and update actions only accept POST requests
    // def allowedMethods = [delete:'POST', save:'POST', update:'POST']

    def list = {
    response.setHeader("Cache-Control", "no-store")
    def bookList = Book.list(params)
    render(contentType:"text/xml") {
    data {
    for(i in bookList) {
    book {
    id(i.id)
    isbn(i.isbn)
    title(i.title)
    author(i.author)
    price(i.price)
    format(i.format)
    }
    }
    }
    }
    }

    def save = {
    def book
    if(params.id) {
    book = Book.get(params.id)
    }
    else {
    book = new Book()
    }
    book.properties = params
    book.save()
    render ""
    }

    def delete = {
    def book = Book.get(params.id)
    if(book) {
    book.delete()
    }
    render ""
    }

    }


    What you can see here is that the list action return xml data which will be used by Flex. Important is setting the cache control in the response header. The save action will be used both creating as editing.

  4. Create a new Flex project (in Flex builder) and replace the code in the main mxml file with:
    <?xml version="1.0" encoding="utf-8"?>
    <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" creationComplete="listService.send()">

    <mx:HTTPService id="listService" url="http://localhost:8080/flexongrails/book/list" useProxy="false" method="GET"/>
    <mx:HTTPService id="saveService" url="http://localhost:8080/flexongrails/book/save" useProxy="false" method="POST" result="listService.send()">
    <mx:request xmlns="">
    <id>{book_id.text}</id>
    <isbn>{isbn.text}</isbn>
    <title>{title.text}</title>
    <author>{author.text}</author>
    <price>{price.text}</price>
    <format>{format.text}</format>
    </mx:request>
    </mx:HTTPService>
    <mx:HTTPService id="deleteService" url="http://localhost:8080/flexongrails/book/delete" useProxy="false" method="POST" result="listService.send()">
    <mx:request xmlns="">
    <id>{dg.selectedItem.id}</id>
    </mx:request>
    </mx:HTTPService>

    <mx:NumberFormatter id="priceFormatter" precision="2"/>

    <mx:Script>
    <![CDATA[
    [Bindable]
    private var formatArray:Array = ["Hardcover", "Paperback", "e-Book"];

    private function clearForm():void {
    book_id.text = "";
    isbn.text = "";
    title.text = "";
    author.text = "";
    price.text = "";
    format.selectedIndex = 0;
    }

    private function formatPrice(item:Object, column:DataGridColumn):String {
    return priceFormatter.format(item.price);
    }
    ]]>
    </mx:Script>

    <mx:VDividedBox x="0" y="0" height="100%" width="100%" paddingLeft="10" paddingRight="10" paddingTop="10" paddingBottom="10">
    <mx:Panel width="100%" height="300" layout="absolute" title="Create/Update Book">
    <mx:Form x="10" y="10" width="930" height="200">
    <mx:FormItem label="ID">
    <mx:TextInput width="120" id="book_id" text="{dg.selectedItem.id}" enabled="false"/>
    </mx:FormItem>
    <mx:FormItem label="ISBN">
    <mx:TextInput width="220" id="isbn" text="{dg.selectedItem.isbn}" maxChars="20"/>
    </mx:FormItem>
    <mx:FormItem label="Title">
    <mx:TextInput width="320" id="title" text="{dg.selectedItem.title}" maxChars="50"/>
    </mx:FormItem>
    <mx:FormItem label="Author">
    <mx:TextInput width="320" id="author" text="{dg.selectedItem.author}" maxChars="50"/>
    </mx:FormItem>
    <mx:FormItem label="Price">
    <mx:TextInput width="120" id="price" text="{priceFormatter.format(dg.selectedItem.price)}"/>
    </mx:FormItem>
    <mx:FormItem label="Format" width="220">
    <mx:ComboBox id="format" selectedIndex="{formatArray.indexOf(dg.selectedItem.format)}">
    <mx:dataProvider>{formatArray}</mx:dataProvider>
    </mx:ComboBox>
    </mx:FormItem>
    </mx:Form>
    <mx:ControlBar horizontalAlign="right">
    <mx:Button label="New" click="clearForm()"/>
    <mx:Button label="Save" click="saveService.send(); clearForm()"/>
    </mx:ControlBar>
    </mx:Panel>
    <mx:Panel width="100%" height="444" layout="absolute" title="Book List">
    <mx:DataGrid x="0" y="0" width="100%" height="100%" id="dg" dataProvider="{listService.lastResult.data.book}">
    <mx:columns>
    <mx:DataGridColumn width="120" headerText="ID" dataField="id"/>
    <mx:DataGridColumn width="220" headerText="ISBN" dataField="isbn"/>
    <mx:DataGridColumn width="320" headerText="Title" dataField="title"/>
    <mx:DataGridColumn width="320" headerText="Author" dataField="author"/>
    <mx:DataGridColumn width="120" headerText="Price" dataField="price" labelFunction="formatPrice"/>
    <mx:DataGridColumn width="220" headerText="Format" dataField="format"/>
    </mx:columns>
    </mx:DataGrid>
    <mx:ControlBar horizontalAlign="right">
    <mx:Button label="Delete" click="deleteService.send()" enabled="{dg.selectedItem != null}"/>
    </mx:ControlBar>
    </mx:Panel>
    </mx:VDividedBox>

    </mx:Application>

  5. Run the Flex application


You now have a basic CRUD Flex application which uses Grails as back-end. The example is very basic and the Grails Book controller isn't responding back any possible validation errors; they just get absorbed. Also for a couple of row retrieving all the rows at once is no problem, but in real life it will me thousands and thousands of records, so also server side paging and ordering is needed. Well, this could be easily implemented in the Book controller (as it is basic Grails functionality) but most of the work will go in the Flex application I think...

For server-side paging/sorting a custom Flex component would be needed which remembers the current page and just submits the required paging and sorting fields to the serve-side. This is independent to Grails as it could be used by any server-side application. I guess I'm not the first one looking into this so I might find something on the internet.

Friday, July 27, 2007

Java Summer Camp in The Netherlands with Rails and Grails



This years Profict Java Summer Camp will host both Charles Nutter and Graeme Rocher to speak about JRuby and Grails.

This Java Summer Camp is hold on August 24 in The Netherlands. I will be there myself and I'm looking forward to meet other Grails users. Exciting!

If you are interested you can find more information on http://javasummercamp.nl.

Thursday, July 26, 2007

Sexy Flexy Grails



Competition in the RIA space is heating up lately. Adobe Flex is already here for some time, and with the announcement of JavaFX and Microsoft Silverlight recently a real RIA WAR has been started. I had a look af Adobe Flex some time ago and I must say my first impression is WOW! These Flash/Flex applications feel so natural!

With Flex you can create rich internet applications with highly interactive GUI's. It offers various methods for talking with server-side components to retrieve and store data. You can use simple HTTP GET/POST services, WEB services, RPC calls or Flex Data Services.

Using HTTP GET/POST or WEB services gives you the freedom to choose the server-side technology: PHP, Servlets, JSP, Ruby on Rails etc.

Mike Potter already has written a small tutorial about integrating Flex and PHP.

I will use Mike's tutorial to show you how easy it is to integrate Flex and Grails.

Prerequisites: I assume you have basic understanding of Flex and Grails and that you have installed them both already.

Where to start:
  1. First read Mike's tutorial about integrating Flex and PHP. After reading it you will understand that a simple PHP page is used to retrieve/return User records in XML data and to store new User records. In the next steps we will do the same, but then using Grails.
  2. It's time to create a new Grails application so from the command line type:
    grails create-app sexyflexygrails
  3. Create the User domain class:
    grails create-domain-class User
    It's not needed to create the User table like in the PHP tutorial. Grails will automatically create the table when you run the application.

  4. Add the Username and Emailaddress properties to the created domain class:
    class User { 
    String username
    String emailaddress
    }
  5. reate a new controller to retrieve and store data:
    grails create-controller User
  6. Implement the needed logic in the created UserController:
    class UserController {
    def index = {
    if (params.username && params.emailaddress) {
    def user = new User()
    user.properties = params
    user.save()
    }

    def userList = User.list()
    render(contentType:"text/xml") {
    users {
    for(i in userList) {
    user {
    userid(i.id)
    username(i.username)
    emailaddress(i.emailaddress)
    }
    }
    }
    }
    }
    }
    When the index action is called it will check if the Username and Emailaddress parameters are in request parameters, and if so it will create a new User. In any case, the call to the index action will return all Users in the database as XML. Flex will use this XML to display the Users in a table.
  7. That's it for the server-side Grails part. Start the Grails application with:
    grails run-app
  8. Open a browser and goto http://localhost:8080/sexyflexygrails/user. You will see no data as there is nothing in the database yet. Try adding a new User with http://localhost:8080/sexyflexygrails/user?username=MyUsername&emailaddress=MyUsername@MyCompany.com. This will create the new User in the database and will render the XML in the browser.
  9. Now start Flex Builder and create a new Flex project. Chooser Other/None as Server type.
  10. Open the automatically created main mxml file and copy in the MXML code from Mike's tutorial: http://www.adobe.com/devnet/flex/articles/flex2_php_03.html
  11. In the MXML code change the HTTPService url to: http://localhost:8080/sexyflexygrails/user
  12. Now run the Flex application and it will use Grails for retrieving and storing the data from the back-end.

In the next weeks I will have a further look at Flex, and see if I can create a small Flex CRUD application that uses Grails at the server-side. I will post my findings here, so stay tuned.

Sunday, March 25, 2007

Google Personalized Homepage




I think a week ago or something I enabled the Google Personlized Homepage, which resulted in a homepage full of news feeds relevant to my locale settings. This weekend I customized my homepage, by removing and adding Google Gadgets. I ended up with a single homepage containing a couple of news feeds of pages I normally read, a ToDO list, simple GMail & Google Calendar integration, localized weather news, Babelfish translation and a Wikipedia search box. And all of this on just 1 page!

The Google Gadgets directory contains a lot of useful Gadgets and news feeds. If the RSS or Atom feed is not in the directory (yet), you can also directly add an item to your personlized page by pointing to a RSS or Atom url.

Off course I created a new personlized page containing all the news feeds related to Grails, so I can see the latest activity very easily ;-)

If you want to add them to your own personlized page just click the links below:

Grails Announcements Add to Google

Grails User List Add to Google

Grails Dev List Add to Google

Grails JIRA Activity Add to Google

Grails Build Status Add to Google

Monday, March 12, 2007

Grails Frappr Map

Recently I've created a Grails Frappr Map to see where the Grails users and committers are located. It's just nice to know where people you talk to on the mailing lists live. And maybe you will find out your neighbor is also using Grails!


Monday, February 26, 2007

Getting Dynamic with Grails' ExpandoMetaClass



In Grails 0.4 the ExpandoMetaClass was introduced that allows you to dynamically add methods, constructors, properties and static methods using a neat closure syntax.

A posting on the Grails User Forum today (see http://www.nabble.com/Newbie---Need-to-implement-a-soft-) gave me a perfect example to explain and show the power of what is possible with this ExpandoMetaClass.

The question on the forum was how the dynamic delete method could be overridden by a 'soft' delete. This meaning a deleted flag set to true and the record to be saved.

In this example I'm not implementing this exact functionality. It just gave me the idea for this post. Imagine you never want to delete records from your databse, but always want just want to mark them. For example to implement some Recycle Bin functionality in which you can later restore records or delete them forever.


What you would need is to define a dynamic "softDelete()" method for all domain classes which sets the deleted flag and updates the record. Actually with the ExpandoMetaClass it's so simple.

In the init closure of the ApplicationBootStrap.groovy class you can do some bootstrapping for your application. This bootstrap class is often used to insert some "demo" records. For example the simple-cms sample application included in the Grails distribution does this. But wihtin this bootstrap class you also use the ExpandoMetaClass to define dynamic methods. See the code below:



import org.codehaus.groovy.grails.commons.metaclass.*
import org.codehaus.groovy.grails.commons.GrailsApplication

class ApplicationBootStrap {

def init = { servletContext ->

// get application
def application = servletContext.getAttribute(GrailsApplication.APPLICATION_ID)

// define softDelete() method for all domain classes
application.domainClasses.each { dc ->
dc.metaClass.softDelete << { ->
delegate.deleted = true
delegate.save()
}
}
}
def destroy = {
}
}

Note that the code above assumes that all domain classes have a "deleted" boolean property. This could be added to all domain classes or perhaps been added dynamically. But it's out of scope for this example.
To check if it's working you can do some test like:


// create new book
new Book(title:'The Definitive Guide to Grails').save()

// retrieve saved book
def savedBook = Book.get(1)
assert savedBook.deleted == false

// now softDelete the book
savedBook.softDelete()

// retrieve it again
def softDeletedBook = Book.get(1)
assert savedBook.deleted == true

Wednesday, January 31, 2007

Grails 0.4 Released!



Grails 0.4 has been released today! You can download it from: http://grails.org/Download

Notable improvements include:

Read the full announcement at http://www.nabble.com/-groovy-user--Grails-0.4-Released!-tf3150030.html. Change log at http://jira.codehaus.org/browse/GRAILS?report=com.atlassian.jira.plugin.system.project:changelog-panel.

Thursday, January 25, 2007

First public Grails based site



Marc Palmer has posted his experiences with developing a Grails based site for one of PepsiCo UK's well known juice brands, Copella: http://www.copellafruitjuices.co.uk

Read the full story here: http://www.nabble.com/Major-UK-brand-launches-Grails-based-site-tf3081890.html


Monday, January 22, 2007

Switching to Google



This weekend I switched with both my email and blog to Google. Google is really offering great integrated services like email, blogging, calendar, sharing docs and spreadsheets etc. And I think their portfolio of services will only increase.

Thursday, January 18, 2007

Grails Templating



Since Grails 0.4 (not yet released, but downloadable as snapshot), you can customize how Grails creates/generates artifacts and scaffoldig.

The creation of artifacts like domain classes, controllers, services etc., but also the generation of the scaffolding controller and views, are now template based. As Grails developer you will notice no difference in contrast to previous version, as the the Grails distribution has default templates embedded.

However, for customizing your project needs, you can now take the advantage of customizing these templates for each application. These customization may vary from just extending a BaseController to completely customized layout in the views. Especially customizing the generated HTML in the views offers a lot of potential for developing your applications faster. Changing the same HTML code in generated views is time consuming, but with the customized templates you just do it once, and get it anywhere!

To customize the templates you will need to install the templates. Go into your project's basedir and type:
grails install-templates

This will install the templates in the src/templates folder of your project. Two kind of templates will be installed: artifact and scaffolding templates. The artifact templates are templates which will be used when creating artifacts with the create-xxx command line tools. The scaffolding templates will be used for scaffolding. There are scaffolding templates for the controller and for each view (list.gsp, create.gsp, edit.gsp, show.gsp).

After installing the templates, Grails will use these templates instead of the embedded default templates. If you later don't want to use customized templates anymore, just delete the customized templates from your project and the embedded default templates will be used again.

See also http://www.grails.org/Artifact+and+Scaffolding+Templates.

Thursday, January 11, 2007

I'm part of the team!



In my last blog entry (ages ago already; shame on me) I pointed to a new and very interesting web application framework: Grails.

As I was playing with Grails at home I became more and more enthusiastic about it. In the meantime the popularity of Grails also increased heavily: blog entries, forum usage, screencasts, presentation at JavaPolis, the Grails book etc. Last December I started diving in the Grails source code myself and as a matter of fact I joined the Grails development team this week, and I'm really pleased with this!