In this article, you will build a Web application using Grails, and deploy it on Apache Geronimo. Following is the software you need installed to follow along.
- Java Development Kit
- Both Grails and Geronimo require a Java Development Kit. Grails needs only Java V1.4, but Geronimo needs V1.5. That is because it is a Java EE V5-certified application server, and Java EE V5 uses Java V1.5 features such as annotations and generics. In this article, we use Java SE V1.6_05.
- Groovy programming language
- Grails uses the Groovy programming language, but this is included with Grails, so there are no additional downloads. Grails also uses many best-of-breed products, such as Hibernate and Spring, but these are also included with Grails.
- Grails
- This article uses Grails V1.0.2.
- Apache Geronimo
- This article uses Apache Geronimo V2.1.1. You can use either Geronimo with Tomcat or Jetty, but this article used the Jetty distribution.
- MySQL
- This article uses MySQL V5.0.41, but you should be able to use any database supported by Hibernate.
This article is not an introduction to Grails. You should already be familiar with Grails, though you could probably get by if you are familiar with Ruby on Rails and Java. The Resources section has some good articles to get you up to speed on Grails.
To demonstrate how you can use Grails and Geronimo together, you will build a simple application with Grails, then deploy and enhance it with Geronimo. For your application, you will build a simple ad network. Here is a quick breakdown of the use cases of the application:
- An advertiser can register on the network. All that's needed is a name and password.
- An advertiser can log in to the network.
- An advertiser can create an ad. The ad will have a title, text, and a URL for an image. It will also have a start and end date, a bid, and keywords. The keywords determine when the ad gets displayed, and the bid is used for priority when multiple ads have the same keyword.
- An affiliate can call a Web service to get a list of ads. The affiliate will provide a keyword and a maximum number of ads.
This is a pretty simple application. The Grails ad network is unlikely to supplant Google or Yahoo!, but it does let us touch many of the attractive features of Grails. Let's take a look at some of those features now and see how they enable us to rapidly develop the ad-network application using Grails.
Grails leverages the principles of convention over configuration and don't repeat yourself to greatly reduce the amount of code you need to write for a typical Web application. You will kick-start your development using some of the Grails code-generation scripts.
Let's call the application adserver. You will start by using the Grails command generate-app. You will not spend too much time with how this command
works (see Resources if you are unfamiliar with it). What
is important is that your application is set up according to the Grails conventions.
Not only is it crucial for the Grails framework to know where to find classes and
configuration metadata but it will also make it much easier to package and deploy your
application. Figure 1 shows a snapshot of what this directory structure should look like.
Figure 1. The adserver application structure
Grails encourages a bottom-up development process, where you usually start by defining
your domain models. You can use the Grails command create-domain-class to help with this. The first model you will
create is your Advertiser model, as shown in Listing 1.
Listing 1. The
Advertiser class
class Advertiser {
static hasMany = [ads:Ad]
String name
String password
}
|
This class is pretty simple, as you would expect if you were familiar with Grails or
Groovy in general. The most complicated thing here is the hasMany line. This indicates that an Advertiser can have multiple Ads. Let's
take a look at the Ad class.
Listing 2. The
Ad class
class Ad {
static belongsTo = [advertiser:Advertiser]
String title
String imageUrl
String text
String keywords
Date startDate
Date endDate
Integer bid
}
|
This class is also pretty simple, with the other end of the one-to-many relationship
between it and the Advertiser class. You could now use the
Grails script generate-all to create scaffolding code
(controller classes and GNU Server Pages (GSP) views for all CRUD actions) for each of these classes,
then run the application using the run-app command. This is
optional, but especially useful if you are new to Grails. It gives you good examples of
how to use the domain classes, as well as how to write a controller and a view. We need
this knowledge to create more customized controllers and views for your application.
The first thing you will want to do is let your users (advertisers) register. Create a
RegisterController. Its code is shown in Listing 3.
Listing 3. The
RegisterController
class RegisterController {
def index = { }
def save = {
def exists = Advertiser.findWhere(name:params.name)
if (exists){
flash.message = "The name " + params.name + " is already taken"
redirect(action:index)
}
def advertiser = new Advertiser()
advertiser.properties = params
advertiser.save(flush:true)
session.advertiser=advertiser
redirect(controller:"ad",action:"adsFor")
}
}
|
The main thing this does is check to see if the name the advertiser picked has
already been taken. If it has, an error message is created and you redirect to the
index page. If the name is not taken, the advertiser is created. I put the Advertiser instance in the session, so I do not have to look it up
again, and I redirect to the Ad controller. You will look
at that class soon, but first you need to let the advertiser log in. The Login controller is shown in Listing 4.
Listing 4.
Login controller
class LoginController {
def index = { }
def login = {
def advertiser = Advertiser.findWhere(
name:params.name , password:params.password )
if (!advertiser){
flash.message = "The password does not match the name of the advertiser"
redirect(action:index)
}
session.advertiser=advertiser
redirect(controller:"ad",action:"adsFor")
}
}
|
This is another simple Groovy class. It simply checks if the name and password
match up to the database. If it does, it sets the advertiser in the session and
forwards to the same action in the Ad controller you first
saw in the Register controller. Before moving on to the
Ad controller, you might have noticed that the controller
methods make direct use of domain-object data-access code. An alternative would be to use a service layer.
The best practice here would be to factor out the Advertiser.findWhere code seen in the RegisterController and LoginController to a service
layer. To do so, you can use the Grails command create-service and refactor your code to move business logic to the
service class. For the register/login scenario shown above, it might look something like Listing 5.
Listing 5. Sample
AdvertiserService
class AdvertiserService {
boolean transactional = true
def advertiserExists(String name){
def exists = Advertiser.findWhere(name:name)
exists != null
}
def login(String name, String password){
Advertiser.findWhere(name:name, password:password)
}
}
|
Remember, Grails is built on proven Java technology such as the Spring framework. A Grails service class becomes a Spring bean. Your service will be a singleton by default, just like it would be if you were using Spring directly. It can also be injected to other Spring beans, and all controllers happen to be Spring beans as well. Convention over configuration kicks in again here and makes it easy to reference the service in a controller.
Listing 6. Using a service in a controller
class LoginController {
def advertiserSerivce
def index = { }
def login = {
def advertiser = advertiserService.login(params.name, params,password)
if (!advertiser){
flash.message = "The password does not match the name of the advertiser"
redirect(action:index)
}
session.advertiser=advertiser
redirect(controller:"ad",action:"adsFor")
}
}
|
By simply having a member variable following the xyzService convention, Grails knows to inject the xyzService singleton. In this sample, you will keep things simple and will not worry too much about a service layer. However, it is important to recognize this as a feature of Grails that really sets it apart from many other rapid-development/convention-over-configuration frameworks. Let's get back to the application code and look at how ads are created and served.
So far, we have two controllers — one for registering and one for logging
into the ad network. Both controllers forward control to another controller: the AdsController.
Listing 7. The
AdsController
import grails.converters.XML
class AdController {
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', placement:'GET']
def adsFor = {
render(view:"list", model:[adList: Ad.findAllWhere(advertiser :
session.advertiser )]);
}
def list = {
if(!params.max) params.max = 10
[ adList: Ad.list( params ) ]
}
def placement = {
def ads = Ad.findAll("from Ad as ad where ad.keywords like
'%"+params.keyword+"%' order by ad.bid desc")
render ads as XML
}
def show = {
def ad = Ad.get( params.id )
if(!ad) {
flash.message = "Ad not found with id ${params.id}"
redirect(action:list)
}
else { return [ ad : ad ] }
}
def delete = {
def ad = Ad.get( params.id )
if(ad) {
ad.delete()
flash.message = "Ad ${params.id} deleted"
redirect(action:list)
}
else {
flash.message = "Ad not found with id ${params.id}"
redirect(action:list)
}
}
def edit = {
def ad = Ad.get( params.id )
if(!ad) {
flash.message = "Ad not found with id ${params.id}"
redirect(action:list)
}
else {
return [ ad : ad ]
}
}
def update = {
def ad = Ad.get( params.id )
if(ad) {
ad.properties = params
if(!ad.hasErrors() && ad.save()) {
flash.message = "Ad ${params.id} updated"
redirect(action:show,id:ad.id)
}
else {
render(view:'edit',model:[ad:ad])
}
}
else {
flash.message = "Ad not found with id ${params.id}"
redirect(action:edit,id:params.id)
}
}
def create = {
def ad = new Ad()
ad.properties = params
return ['ad':ad]
}
def save = {
def ad = new Ad(params)
if (session.advertiser){
ad.advertiser = session.advertiser
}
if(!ad.hasErrors() && ad.save()) {
flash.message = "Ad ${ad.id} created"
redirect(action:show,id:ad.id)
}
else {
render(view:'create',model:[ad:ad])
}
}
}
|
If you have used the scaffolding command (generate-all ad),
you will recognize much of this code. It has been customized in several ways though. You
added the adsFor method, as this is what we have been
forwarding to from the register and login controllers. This uses the advertiser from
the session to get all the ads owned by the advertiser, then renders this with the
"list" view. The save method has also been modified to use
the advertiser from the session. Finally, the placement method has been added. This is
the method that will be used by affiliates to retrieve ads. It takes a keyword parameter and gets all the ads with that keyword. It uses a
custom query that uses the Hibernate Query Language, which is a REST Web service that
uses XML to serialize the data. Grails makes this easy by simply returning render ads
as XML. You have not had to add much code to customize your application to handle all
your use cases. You can quickly find out just how little code you have actually written
using the Grails stats command.
Listing 8. Ad-server application stats
$ grails stats
Welcome to Grails 1.0.2 - http://grails.org/
Licensed under Apache Standard License 2.0
Grails home is set to: /Users/michael/lib/grails-1.0.2
Base Directory: /Users/michael/code/grails/adserver
Note: No plugin scripts found
Running script /Users/michael/lib/grails-1.0.2/scripts/Stats.groovy
Environment set to development
+----------------------+-------+-------+
| Name | Files | LOC |
+----------------------+-------+-------+
| Controllers | 4 | 179 |
| Domain Classes | 2 | 15 |
| Services | 1 | 10 |
| Integration Tests | 5 | 20 |
+----------------------+-------+-------+
| Totals | 12 | 224 |
+----------------------+-------+-------+
|
That is not a whole lot of code. Actually, most of it is code you generated using
the generate-all scaffolding for advertiser and ad. Grails
makes it easy to develop by not making you write much code. It also makes it easy to develop by making it easy to test.
To run the application, simply issue the Grails command run-app. This invokes a script that uses an embedded in-memory database and an
embedded Jetty Web container, so you do not need to set up a stand-alone server or
database. You should be able to immediately go to http://localhost:8080/adserver and access your
controllers, etc. Once you have tested and debugged your application, you are ready to start using it with Geronimo.
So now you have developed a Web application that satisfies all of your use cases. You were able to develop it rapidly and had to write less code because you took advantage of Grails. Of course, less code is obviously a relative term — less code compared to what? The obvious answer is a typical Java Web application. There is no question that Grails lets you develop faster and write less code than a typical Java Web application, but is there a cost to this? The good news is that a Grails application is a Java Web application. Grails lets you package it up as a standard Java Web application, a WAR, and deploy it to any Java Web container — including Apache Geronimo. Let's take a look at how you deploy your Grails ad-server application to Geronimo.
The first step in deploying our Grails application to Geronimo is to create a WAR.
Looking at the Grails directory structure, it would not be too hard to write an Ant
script to do this, but luckily, Grails make it even easier by providing a simple Grails
command: war. The script compiles code from the grails-app
tree and combines it with code from the base Grails ($GRAILS_HOME) directory.
The result is added to the /web-app directory. Since you are using Geronimo, you need
to add a Geronimo deployment plan. You can simply create a geronimo-web.xml file in /web-app/WEB-INF.
Listing 9. Geronimo deployment plan
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://geronimo.apache.org/xml/ns/j2ee/web-1.1">
<environment xmlns="http://geronimo.apache.org/xml/ns/deployment-1.1">
<moduleId>
<groupId>grailsApps</groupId>
<artifactId>AdServer</artifactId>
<version>0.1</version>
<type>war</type>
</moduleId>
<hidden-classes>
<filter>org.springframework</filter>
<filter>org.apache.cxf</filter>
<filter>org.apache.commons</filter>
</hidden-classes>
</environment>
<context-root>/adserver</context-root>
</web-app>
|
There is one very important thing to notice here, and that is the hidden-classes section. These are packages that are included by default with Geronimo, but are also included with Grails. This tells the class loader that will load our Grails app, to ignore any classes from these packages available to the parent class loader (i.e., the container's class loader). This will guarantee that the Grails versions of these classes are loaded and we will not have any nasty class-loader conflicts.
Now you are ready to run the Grails war command. Listing 10
shows the command being run and the output of the command.
Listing 10. Using the
war command
$ grails war
Welcome to Grails 1.0.2 - http://grails.org/
Licensed under Apache Standard License 2.0
Grails home is set to: /Users/michael/lib/grails-1.0.2
Base Directory: /Users/michael/code/grails/adserver
Note: No plugin scripts found
Running script /Users/michael/lib/grails-1.0.2/scripts/War.groovy
Environment set to production
[delete] Deleting: /Users/michael/.grails/1.0.2/projects/
adserver/resources/web.xml
[delete] Deleting directory /Users/michael/.grails/1.0.2/projects/adserver/classes
[delete] Deleting directory /Users/michael/.grails/1.0.2/projects/adserver/resources
[mkdir] Created dir: /Users/michael/.grails/1.0.2/projects/adserver/classes
[groovyc] Compiling 13 source files to /Users/michael/.grails/1.0.2/
projects/adserver/classes
[mkdir] Created dir: /Users/michael/.grails/1.0.2/projects/adserver/
resources/grails-app/i18n
[native2ascii] Converting 10 files from /Users/michael/code/grails/adserver/
grails-app/i18n to /Users/michael/.grails/1.0.2/projects/adserver/resources/
grails-app/i18n
[copy] Copying 1 file to /Users/michael/.grails/1.0.2/projects/adserver/classes
[copy] Copying 1 file to /Users/michael/.grails/1.0.2/projects/adserver/resources
[mkdir] Created dir: /Users/michael/code/grails/adserver/staging
[copy] Copying 93 files to /Users/michael/code/grails/adserver/staging
[copy] Copied 19 empty directories to 1 empty directory under /Users/michael/
code/grails/adserver/staging
[copy] Copying 23 files to /Users/michael/code/grails/adserver/staging/
WEB-INF/grails-app
[copy] Copying 55 files to /Users/michael/code/grails/adserver/staging/
WEB-INF/classes
[mkdir] Created dir: /Users/michael/code/grails/adserver/staging/
WEB-INF/spring
[copy] Copying 1 file to /Users/michael/code/grails/adserver/staging/
WEB-INF/classes
[mkdir] Created dir: /Users/michael/code/grails/adserver/staging/
WEB-INF/templates/scaffolding
[copy] Copying 6 files to /Users/michael/code/grails/adserver/staging/
WEB-INF/templates/scaffolding
[copy] Copying 50 files to /Users/michael/code/grails/adserver/staging/
WEB-INF/lib
[copy] Copying 1 file to /Users/michael/code/grails/adserver/staging/
WEB-INF
[delete] Deleting: /Users/michael/.grails/1.0.2/projects/adserver/resources/web.xml
[copy] Warning: /Users/michael/code/grails/adserver/plugins not found.
[propertyfile] Updating property file: /Users/michael/code/grails/adserver/staging/
WEB-INF/classes/application.properties
[mkdir] Created dir: /Users/michael/code/grails/adserver/staging/WEB-INF/plugins
[copy] Warning: /Users/michael/code/grails/adserver/plugins not found.
[jar] Building jar: /Users/michael/code/grails/adserver/adserver-0.1.war
[delete] Deleting directory /Users/michael/code/grails/adserver/staging
Done creating WAR /Users/michael/code/grails/adserver/adserver-0.1.war
|
To deploy the WAR, you can simply add it to the Geronimo deployment directory ($GERONIMO_HOME/deploy, where $GERONIMO_HOME is the location of your Geronimo installation) or you can use the Geronimo Console.
Figure 2. Using the Geronimo console to deploy Grails WAR
In the Geronimo deployment plan in Listing 9, we set the context path of the application to /adserver, so http://localhost:8080/adserver will bring up our deployed application. Now that our Grails application is running on Geronimo, let's look at how Geronimo can be used to enhance the application.
It is common knowledge that you can gain a lot of performance benefits by using database connection pools. You save the significant overhead of creating a database connection on every request to your Web application. Thus, it is very common to set up a database connection pool in Java Web applications. An application server like Geronimo makes it even easier to create such a pool that can be reused by any application deployed on Geronimo. You can create a pool easily from the Geronimo console, as shown in Figure 3.
Figure 3. Creating a database pool in Geronimo
Now that the database pool has been created, we just need to access it from our Grails application. There are a couple of steps we need to do for this.
Accessing a database pool from Grails
The database pool is represented as a Java DataSource object
and it is bound in JNDI, so any application can use it. For this to exist in the context
of a Web application, it needs to be referenced in our web.xml file. Wait a minute
— what web.xml? Grails creates one for us that it bases off of
$GRAILS_HOME/conf/webdefault.xml. You could edit that, or you could generate the WAR,
unzip it, and edit the generated one. Either way, you will need to add the section shown in Listing 11 to it.
Listing 11. Referencing a
DataSource in web.xml
<resource-ref>
<res-ref-name>jdbc/MyDataSource</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
<res-sharing-scope>Shareable</res-sharing-scope>
</resource-ref>
|
This can usually be added just before the end of the web.xml file. Next, we need to add a reference to our Geronimo deployment plan.
Listing 12. New Geronimo deployment plan
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://geronimo.apache.org/xml/ns/j2ee/web-1.1">
<environment xmlns="http://geronimo.apache.org/xml/ns/deployment-1.1">
<moduleId>
<groupId>grailsApps</groupId>
<artifactId>AdServer</artifactId>
<version>0.1</version>
<type>war</type>
</moduleId>
<hidden-classes>
<filter>org.springframework</filter>
<filter>org.apache.cxf</filter>
<filter>org.apache.commons</filter>
</hidden-classes>
<dependencies>
<dependency>
<groupId>console.dbpool</groupId>
<artifactId>adserver</artifactId>
</dependency>
</dependencies>
</environment>
<context-root>/adserver</context-root>
<resource-ref>
<ref-name>jdbc/MyDataSource</ref-name>
<resource-link>adserver</resource-link>
</resource-ref>
</web-app>
|
Note that we called our database pool adserver and that is
the resource-link you see in the resource-ref and the dependency. The ref-name in the deployment plan must match the res-ref-name in the web.xml snippet in Listing 11. This connects the
dots between Geronimo and your Web application.
Now the connection pool is available to the application. So how do you access it? Turns out that Grails makes this part easy. All we need to do is edit /grails-app/conf/DataSource.groovy.
Listing 13. DataSource.groovy
dataSource {
jndiName = "java:comp/env/jdbc/MyDataSource"
}
hibernate {
cache.use_second_level_cache=true
cache.use_query_cache=true
cache.provider_class='org.hibernate.cache.EhCacheProvider'
}
// environment specific settings
environments {
development {
dataSource {
dbCreate = "update"
}
}
test {
dataSource {
dbCreate = "create-drop"
}
}
production {
dataSource {
dbCreate = "create"
}
}
}
|
Normally, the first dataSource block is where we define JDBC
properties, like driver class, username, password, etc. Now we simply provide the JNDI
name. This name must be "java:comp/env/" plus whatever you put for the res-ref-name in the web.xml file. You can override all of these
settings for any of your environments, just like you normally would.
You have seen how Grails makes it possible to rapidly build a Web application. Its use of convention over configuration makes a lot of popular technologies fuse together with no effort. You follow the conventions and Grails makes your life easy. You still have to write code for your business logic, but even that code is minimal, courtesy of the expressiveness of the Groovy programming language. Grails with Geronimo just gives this happy story an even happier ending. You are able to leverage all the power of Geronimo as our Grails application runs just like any other Java Web application and can access Geronimo resources in a similar fashion. From here, you can make your Grails application more sophisticated by using more Geronimo features like messaging, or you could make it more scalable by deploying it to a Geronimo cluster.
| Description | Name | Size | Download method |
|---|---|---|---|
| Sample code | os-ag-grails.adserver.example.zip | 829KB | HTTP |
Information about download methods
Learn
-
"Mastering
Grails: Build your first Grails application" is necessary if you're new to Grails.
-
Read "Mastering Grails: GORM: Funny name, serious technology" to learn all
about how Grails builds on top of Hibernate to interface with your database.
-
"Mastering
Grails: Changing the view with Groovy Server Pages": Don't like the UI of this app? Learn all the ways to change it.
-
Are you a fan of the succinctness that Groovy provides? Learn all about its concise
syntax by reading "Practically
Groovy: Reduce code noise with Groovy."
-
Groovy is another promising language that compiles to Java bytecode. Read about creating
XML with it in the developerWorks article "Practically Groovy: Mark
it up with Groovy Builders."
-
Grails.org is the best place for Grails information.
-
The Grails manual is every Grails developer's best friend.
-
Take a look at "Grails vs Rails
Performance Benchmarking" to see how Grails has significant advantages over Rails by being on top of Java, Hibernate, and Spring.
-
Deploying an application on Geronimo is easy, but there is a lot that goes on. Learn all
about it in the developerWorks article "Understand
Geronimo's deployment architecture."
-
Read "Remotely deploy
Web applications on Apache Geronimo" to find out how to deploy your Grails applications to remote instances of Geronimo.
-
Learn about other alternative languages running on the JVM in the developerWorks article
"Invoke
dynamic languages dynamically, Part 1."
- Read the latest Geronimo documentation and news on the Geronimo wiki.
-
Get involved in the Geronimo project.
-
Join the Apache Geronimo mailing list.
-
Understand what you need to do to apply the Apache License V2.0.
-
Check out the developerWorks Apache Geronimo project area for
articles, tutorials, and other resources to help you get started developing with Geronimo today.
-
Find helpful resources for beginners and experienced users at the Get started now with Apache Geronimo section of developerWorks.
-
Check out the IBM® Support for
Apache Geronimo offering, which lets you develop Geronimo applications backed by world-class IBM support.
-
Visit the developerWorks Open source zone for extensive
how-to information, tools, and project updates to help you develop with open source technologies and use them with IBM's products.
-
Stay current with developerWorks technical events and webcasts.
-
Browse all the Apache
articles and no-cost
Apache tutorials available in the developerWorks Open source zone.
-
To listen to interesting interviews and discussions for software developers, check out
developerWorks podcasts.
-
Watch and learn about IBM and open source technologies and product functions with the
no-cost developerWorks On demand demos.
Get products and technologies
-
Download the Java SDK.
This article uses Java SE V1.6_05.
-
Download Grails V1.02.
-
This article uses Geronimo V2.1.1.
-
Download MySQL V5.0.41.
- Download the latest version of
Apache Geronimo.
- Download your no-cost copy of IBM WebSphere® Application Server Community Edition — a lightweight J2EE application server built on Apache Geronimo open source technology that is designed to help you accelerate your development and deployment efforts.
- Innovate your next open source development project with IBM trial software, available for download or on DVD.
- Download IBM product evaluation versions and get your hands on application development tools and middleware products from DB2®, Lotus®, Rational®, Tivoli®, and WebSphere®.




