CHAPTER 2

Getting Started with Grails

In Chapter 1, you got your first introduction to the Grails framework and a feel for the basic command-line interface while creating the basis for the gTunes application. In this chapter, we're going to build on that foundation by showing how you can use Grails' scaffolding feature to quickly build a prototype application that can generate simple CRUD (Create, Read, Update, Delete) interfaces.

Then we'll start to explain some of the basic concepts within the Grails ecosystem such as environments, data sources, and deployment. Get ready—this is an action-packed chapter with loads of information!

What Is Scaffolding?

Scaffolding is a Grails feature that allows you to quickly generate CRUD interfaces for an existing domain. It offers several benefits, the most significant of which is that it serves as a superb learning tool, allowing you to relate how Grails' controller and view layers interact with the domain model that you created.

You should note, however, that Grails is not just a CRUD framework. And scaffolding, although a useful feature in your repertoire, is not Grails' main benefit. If you're looking for a framework that provides purely CRUD-oriented features, better options are at your disposal.

As with a lot of Grails features, scaffolding is best demonstrated visually, so let's plunge right in and see what you can do.

Creating a Domain

Grails' domain classes serve as the heart of your application and business-model concepts. If you were constructing a bookstore application, for example, you would be thinking about books, authors, and publishers. With gTunes you have other thoughts in mind, such as albums, artists, and songs.

The most significant attribute that differentiates domain classes from other artifacts within a Grails application is that they are persistent and that Grails automatically maps each domain class onto a physical table in the configured database. (You'll learn more about how to change the database setup later in the chapter.)

The act of mapping classes onto a relational database layer is also known as object-relational mapping (ORM). Grails' ORM layer, called GORM, is built on the ever-popular Hibernate library (http://www.hibernate.org).

Domain classes reside snugly in the grails-app/domain directory. You create a domain class by using the grails create-domain-class helper command, or your favorite IDE or text editor. Type the helper command shown in Listing 2-1 into a command window from the root of the gTunes project.

Listing 2-1. Creating the Song Domain Class

$ grails create-domain-class com.g2one.gtunes.Song

Listing 2-1 shows that you'll be using a package to hold your domain classes. Groovy follows exactly the same packaging rules as Java, and as with Java, it is good practice to use packages. You might not see the benefit of packages in the beginning, but as your application grows and you begin taking advantage of Grails plugins and integrating more Java code, you will appreciate the organization that they provide (for more about plugins, see Chapter 13).

Once the command in Listing 2-1 completes, the result will be a new Song domain class located in the grails-app/domain/com/g2one/gtunes directory as dictated by the package prefix specified. Figure 2-1 shows the newly created structure and the Song.groovy file containing the domain class definition.

image

Figure 2-1. The Song domain class and the Song.groovy file

Currently, the Song domain isn't doing a great deal; it's simply a blank class definition as shown in Listing 2-2.

Listing 2-2. The Song Domain Class

package com.g2one.gtunes
class Song {
}

At this point, you should think about what aspects make up a "Song". Songs typically have a title, an artist, and a duration, among other things. If you really want to go overboard, you could model your Song domain class on all the fields you can populate in an MP3 file's ID3 tag. But in this case, keep it simple: add only the three previously mentioned properties as shown in Listing 2-3.

Listing 2-3. Adding Properties to the Song Domain Class

package com.g2one.gtunes
class Song {
    String title
    String artist
    Integer duration
}

That was simple enough, and the class doesn't look much different from your typical Groovy bean (see the Appendix for information about Groovy beans). GORM essentially maps the class name onto the table name and each property onto a separate column in the database, with their types relating to SQL types. Don't get too hung up on this now; we'll be digging more deeply into domain classes and GORM in Chapters 3 and 10. For the moment, let's move on to seeing the application in action.

Dynamic Scaffolding

Scaffolding comes in two flavors: dynamic (or runtime), and static (or template-driven). First we'll look at dynamic scaffolding, where a CRUD application's controller logic and views are generated at runtime. Dynamic scaffolding does not involve boilerplate code or templates; it uses advanced techniques such as reflection and Groovy's metaprogramming capabilities to achieve its goals. However, before you can dynamically scaffold your Song class, you need a controller.

You had a brief introduction to creating controllers in Chapter 1, and the controller code necessary to enable scaffolding is minimal. Create the controller for the Song class either manually or via the command line, as shown in Listing 2-4.

Listing 2-4. Creating the SongController

$ grails create-controller com.g2one.gtunes.Song

Again, you should use the package prefix with the grails create-controller command, which will create the SongController within the grails-app/controllers/com/g2one/gtunes directory (see Figure 2-2).

image

Figure 2-2. Locating the SongController in the directory

To enable dynamic scaffolding, within the SongController create a scaffold property with the name of the target class as its value. In this case, it is the Song class, as shown in Listing 2-5.

Listing 2-5. Enabling Dynamic Scaffolding

package com.g2one.gtunes
class SongController {
    def scaffold = Song
}

Note Groovy automatically resolves class names, such as Song in Listing 2-5, to the java.lang.Class instance without requiring the .class suffix. In other words Song == Song.class.


With that done, simply start up Grails with the grails run-app command, open a browser, and navigate to the gTunes application at the usual link: http://localhost:8080/gTunes.

The Grails welcome page, first demonstrated in Chapter 1, will show the SongController instance in the list of available controllers as well as the usual comforting welcome message. Click the SongController link to pull up a page listing all the Song objects (perhaps none, as the case may be), as depicted in Figure 2-3.

image

Figure 2-3. The Song List page

Without breaking a sweat, and in a grand total of three lines of code (excluding the package declaration), you have managed to create a useful CRUD interface that lets you create and fully manage the Song instances within the gTunes application.

The Create Operation

The magic doesn't end here. By clicking the "New Song" link at the top of the screen, you can create new songs. While generating the views, Grails does its best to guess what type of field is required to edit a property's value. For example, if Grails finds a String, it will create a text field; if it finds a java.util.Date, it will render drop-down boxes that allow you to select the date and time. Figure 2-4 shows an example of what the generated song-creation interface looks like.

Grails' built-in validation mechanism, called constraints, can also affect how the interface is rendered, including the order in which fields are displayed and the type of field that is rendered. Try clicking the "Create" button; you'll get a validation error stating that the duration must be specified, as pictured in Figure 2-5. The validation messages hook into Grails' internationalization support (often referred to with the abbreviation i18n). But for now, all you need to know is that Grails is pulling these messages from the properties files within the grails-app/i18n directory. (We'll discuss constraints in Chapter 3 and internationalization in Chapter 7.)

image

Figure 2-4. The Create Song page

image

Figure 2-5. How Grails handles validation

You could customize the message at this point, but for now the defaults will do. Now let's try to create a song with some valid data. Specifically, try to enter these values into the provided fields:

Artist: Kings of Leon

Duration: 176000

Title: The Bucket

Now click the "Create" button and move on to the next section of the chapter.

The Read Operation

Grails has obeyed instructions and duly created a new Song instance with the necessary data in the database. You are then redirected to the "Show Song" screen where you can view and admire a rendered view of the Song instance you just created.

Additionally, as pictured in Figure 2-6, the "Show Song" screen provides two buttons to let you edit or delete the Song instance from the database.

image

Figure 2-6. The Show Song screen

Currently, you're dealing with a trivial domain model with only a single Song domain class to account for. However, another attribute of domain classes is that they typically have relationships such as one-to-many, one-to-one, and so on. If you think about a Song for a moment, it is typically part of a collection of Songs within an album. Let's create an Album domain class to model this using the grails create-domain-class command as shown in Listing 2-6.

Listing 2-6. Creating the Album Domain Class

$ grails create-domain-class com.g2one.gtunes.Album

An Album has attributes of its own, such as a title, but it also contains many songs. Listing 2-7 shows how to set up a one-to-many relationship between Album and Song using the hasMany static property of domain classes. The hasMany property is assigned a Groovy map where the key is the relationship name and the value is the class, in this case Song, to which the association relates.

Listing 2-7. Defining a One-to-Many Relationship

package com.g2one.gtunes

class Album {
    String title
    static hasMany = [songs:Song]
}

The preceding association is unidirectional. In other words, only the Album class knows about the association, while the Song class remains blissfully unaware of it. To make the association bidirectional, modify the Song class to include an Album local property as shown in Listing 2-8. Now Album and Song have a bidirectional, one-to-many association.

Listing 2-8. Making the Relationship Bidirectional

package com.g2one.gtunes
class Song {
   ...
   Album album
}

In Chapter 3, we'll delve into other kinds of relationships and how they map onto the underlying database. For now, create another scaffolded controller that can deal with the creation of Album instances. Use the grails create-controller command and add the def scaffold = Album property to the class definition (see Listing 2-9).

Listing 2-9. Scaffolding the Album Class

package com.g2one.gtunes

class AlbumController {
    def scaffold = Album
}

Now if you return to your browser and refresh the Song list, you'll notice that the Song you entered previously has mysteriously vanished. The reason for this is quite simple: Grails by default is running with an in-memory database, and updating domain classes creates a new instance of it. You might find this useful for testing, but you can configure a different database if you require a less volatile storage mechanism (we'll discuss that later in this chapter).

More significant, however, is the fact that on the welcome page we have an additional AlbumController. Click the AlbumController link, followed by the "New Album" button. Enter a title for the Album such as "Aha Shake Heartbreak" and click the "Create" button to see your newly created Album displayed (see Figure 2-7).

image

Figure 2-7. The Show Album screen

You'll also notice that the Album has a blank Songs field. Let's fix that next.

The Update Operation

You can perform updates by clicking the "Edit" button. In this case, you want to add a Song, so click the "Add Song" link to see the "Create Song" interface. This time, you'll get a useful drop-down box that lets you select which Album the Song should be part of (as shown in Figure 2-8). You'll notice that scaffolding's default behavior is simply to call toString() on each element in the drop-down list. The default toString() that Grails provides uses the class name and instance id, which is not the most pleasant thing to present to a user. You can override this behavior by implementing your own toString() method inside the Album class.

Next, populate the fields as described in the "The Create Operation" section and click the "Create" button. You'll notice that the "Show Song" screen provides a link back to the Album; clicking the link shows the Album with the newly created Song instance appearing in the list of songs (see Figure 2-9). Grails' scaffolding, although not exuding genius, is clever enough to figure out what a one-to-many relationship is and how to manage it accordingly.

image

Figure 2-8. The Create Song screen

image

Figure 2-9. Show Album screen with a list of songs

The Delete Operation

Finally, to complete the CRUD acronym, you can delete a particular Song or Album by clicking the "Delete" button. Grails is kind enough to inquire whether you are completely sure that you'd like to proceed with such a destructive operation.

This completes the tour of Grails' dynamic-scaffolding capabilities; in the next section you'll see how to get access to the underlying controller and view code that makes up these CRUD interfaces.

Static Scaffolding

Dynamic scaffolding can serve a number of purposes, from creating administration interfaces to providing the basis of a real application. However, it often becomes useful to take customization to a new level, particularly in terms of views. Fortunately, Grails provides the ability to take a domain class and generate a controller and associated views from the command line through the following targets:

  • grails generate-views: Generates views for the specified domain class
  • grails generate-controller: Generates a controller for the specified domain class
  • grails generate-all: Generates both a controller and associated views

Called "static" or "template-driven" scaffolding, this approach offers benefits beyond simple code generation. Notably, it provides an excellent learning tool to help you familiarize yourself with the Grails framework and how everything fits together.

You've already created a domain model that relates specifically to the problem you're attempting to solve. Now you can generate code that relates to your domain, increasing your chance of understanding the generated code. Let's start by looking at how to generate a controller.

Generating a Controller

To generate a controller that implements the CRUD functionality you saw in the section about dynamic scaffolding, you can take advantage of the grails generate-controller command. Like the other generate commands, generate-controller takes a domain class name as its first argument. For example, Listing 2-10 shows how to use the generate-controller command to output a new controller from the Album class.

Listing 2-10. Outputting a New Controller

$ grails generate-controller com.g2one.gtunes.Album
Generating controller for domain class com.g2one.gtunes.Album ...
File /Developer/grails-dev/apps/gTunes/grailsfigs/U002.jpg
app/controllers/com/g2one/gtunes/AlbumController.groovy already exists.
Overwrite?y,n,a
y
Finished generation for domain class com.g2one.gtunes.Album

Notice that, because the AlbumController class already exists, the generate-controller command will ask whether you want to overwrite the existing controller. Entering the value "y" for "yes" followed by hitting Enter will complete the process.

At this point, you should probably examine the contents of this mysterious controller to see how many thousands of code lines have been generated. If you're coming from a traditional Java web-development background, you might expect to implement a few different classes. For example, you would likely need a controller that calls a business interface, which in turn invokes a Data Access Object (DAO) that actually performs the CRUD operations.

Surely the DAO will contain mountains of ORM framework code, and maybe a few lines of Java Database Connectivity (JDBC) mixed in for good measure. Surprisingly (or not, depending on your perspective), the code is extremely concise at well under 100 lines. That's still not quite short enough to list in full here, but we will step through each action in the generated controller to understand what it is doing.

The index action is the default, which is executed if no action is specified in the controller Uniform Resource Identifier (URI). It simply redirects to the list action, passing any parameters along with it (see Listing 2-11).

Listing 2-11. The index Action

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

The list action provides a list of all albums, as shown in Listing 2-12. It delegates to the static list method of the Album class to obtain a java.util.List of Album instances. It then places the list of Album instances into a Groovy map literal (a java.util.LinkedHashMap under the covers), which is then returned as the "model" from the controller to the view. (You'll begin to understand more about models and how they relate to views in Chapters 4 and 5.)

Listing 2-12. The list Action

def list = {
       if(!params.max) params.max = 10
       [ albumList: Album.list( params ) ]
   }

But hold on a second: before we get ahead of ourselves, have you noticed that you haven't actually written a static list method in the Album class? At this point, you will start to see the power of GORM. GORM automatically provides a whole array of methods on every domain class you write through Groovy's metaprogramming capabilities, one of which is the list method. By looking through this scaffolded code, you will get a preview of the capabilities GORM has to offer.

For example, the show action, shown in Listing 2-13, takes the id parameter from the params object and passes it to the get method of the Album class. The get method, automatically provided by GORM, allows the lookup of domain instances using their database identifiers. The result of the get method is placed inside a model ready for display, as shown in Listing 2-13.

Listing 2-13. The show Action

def show = {
         def album = Album.get( params.id )

         if(!album) {
             flash.message = "Album not found with id ${params.id}"
             redirect(action:list)
         }
         else { return [ album : album ] }
   }

Notice how, in Listing 2-13, if the Album instance does not exist the code places a message inside the flash object, which is rendered in the view. The flash object is a great temporary storage for messages (or message codes if you're using i18n); we'll discuss it in more detail in Chapter 4.

The action that handles deletion of albums is aptly named the delete action. It retrieves an Album for the specified id parameter and, if it exists, deletes it and redirects it to the list action (Listing 2-14).

Listing 2-14. The delete Action

def delete = {
       def album = Album.get( params.id )
       if(album) {
            album.delete()
            flash.message = "Album ${params.id} deleted"
            redirect(action:list)
       }
       else {
           flash.message = "Album not found with id ${params.id}"
           redirect(action:list)
       }
   }

While similar to the show action, which simply displays an Album's property values, the edit action delegates to an edit view, which will render fields to edit the Album's properties (see Listing 2-15).

Listing 2-15. The edit Action

def edit = {
       def album = Album.get( params.id )
       if(!album) {
           flash.message = "Album not found with id ${params.id}"
           redirect(action:list)
       }
       else {
           return [ album : album ]
       }
   }

You might be wondering at this point how Grails decides which view to display, given that the code for the edit and show actions are almost identical. The answer lies in the power of convention. Grails derives the appropriate view name from the controller and action names. In this case, since you have a controller called AlbumController and an action called edit, Grails will look for a view at the location grails-app/views/album/edit.gsp with the album directory inferred from the controller name and the edit.gsp file taken from the action name. Simple, really.

For updating you have the update action, which again makes use of the static get method to obtain a reference to the Album instance. The magical expression album.properties = params automatically binds the request's parameters onto the properties of the Album instance. You then save the Album instance by calling the save() method. If the save succeeds, an HTTP redirect is issued back to the user; otherwise, the edit view is rendered again. You can find the full code in Listing 2-16.

Listing 2-16. The update Action

def update = {
       def album = Album.get( params.id )
       if(album) {
           album.properties = params
           if(!album.hasErrors() && album.save()) {
               flash.message = "Album ${params.id} updated"
               redirect(action:show,id:album.id)
           }
           else {
               render(view:'edit',model:[album:album])
           }
       }
       else {
           flash.message = "Album not found with id ${params.id}"
           redirect(action:edit,id:params.id)
       }
   }

To facilitate the creation of new Albums, the create action delegates to the create view. The create view, like the edit view, displays appropriate editing fields. Note how the create action inserts a new Album into the model to ensure that field values are populated from request parameters (Listing 2-17).

Listing 2-17. The create Action

def create = {
       [album: new Album(params)]
   }

Finally, the save action will attempt to create a new Album instance and save it to the database (see Listing 2-18).

Listing 2-18. The save Action

def save = {
       def album = new Album(params)
       if(!album.hasErrors() && album.save()) {
           flash.message = "Album ${album.id} created"
           redirect(action:show,id:album.id)
       }
       else {
           render(view:'create',model:[album:album])
       }
   }

In both the save and update actions, you alternate between using the redirect and render methods. We'll cover these further in Chapter 4, but briefly: the redirect method issues an HTTP redirect that creates an entirely new request to a different action, while the render method renders a selected view to the response of the current request.

Clearly, we've given only a brief overview of the various CRUD operations and what they do, without elaborating on a lot of the magic that is going on here. There is, however, method in our madness. The nitty-gritty details of controllers and how they work will surface in Chapter 4. For the moment, however, let's try out the newly generated controller by running the gTunes application once again via the grails run-app target.

Once the server has loaded, navigate your browser to the AlbumController at the address http://localhost:8080/gTunes/album. What happens? Well, not a great deal, actually. The result is a page-not-found (404) error because the generated controller is not using dynamic scaffolding. Dynamic scaffolding renders the views at runtime, but what you have here is just a plain old controller—there's nothing special about it, and there are no views.


Note We can of course set the scaffold property to the Album class, and the views will be generated with each action overridden.


Generating the Views

It would be nice to have some views for your actions to delegate to. Fortunately, you can generate them with the grails generate-views command, which is executed according to the same process described in the section "Generating a Controller" (see Listing 2-19).

Listing 2-19. Generating Views

$ grails generate-views com.g2one.gtunes.Album
...
Running script /Developer/grails-dev/grails/scripts/GenerateViews.groovy
...
Generating views for domain class com.g2one.gtunes.Album ...
Finished generation for domain class com.g2one.gtunes.Album

The resulting output from the command window will resemble Figure 2-10.

image

Figure 2-10. The generated scaffolding views

All in all, you can generate four views:

  • list.gsp: Used by the list action to display a list of Album instances
  • show.gsp: Used by the show action to display an individual Album instance
  • edit.gsp: Used by the edit action to edit a Album instance's properties
  • create.gsp: Used by the create action to create a new Album instance

Note All the views use the main layout found at grails-app/views/layouts/main.gsp. This includes the placement of title, logo, and any included style sheets. We'll discuss layouts in detail in Chapter 5.


You now have a controller and views to perform CRUD. So what have you achieved beyond what you saw in dynamic scaffolding? Well, nothing yet. The power of command-line scaffolding is that it gives you a starting point to build your application. Having started with nothing, you now have a controller in which you can place your own custom business logic. You have views, which you can customize to your heart's content. And you accomplished all this while writing minimal code. The developers we know are on a constant mission to write less code, and scaffolding proves a useful tool toward achieving this goal.

With the AlbumController and associated views in place, delete the existing SongController and repeat the steps in Listings 2-10 and 2-19 to generate a controller and views for the Song domain class. You're going to need the generated code as you build on the basic CRUD functionality in later chapters.

In the meantime, let's move on to understanding more of what's necessary to kick-start your Grails development, beginning with environments.

Being Environmentally Friendly

Typically in any web-application production team, you have a development configuration for the application that might be configured to work with a locally installed database. This configuration sometimes even differs from developer to developer, depending on their specific desktop configurations.

In addition, QA staff who test the work produced by developers have separate machines configured in a similar way to the production environment. So we have two environments so far: the development configuration and the test configuration. The third is the production configuration, which you need when the system goes live.

This scenario is ubiquitous across pretty much every development project, with each development team spinning custom automated-build solutions via Ant or another custom-build system, instead of getting the solution from the framework itself.

Grails supports the concept of development, test, and production environments by default and will configure itself accordingly when executed. Some of this is done completely transparently to the developer. For example, autoreloading is enabled when Grails is configured in development mode but disabled when it's in production mode (to increase performance and minimize any security risk, however small).

Executing Grails under different environments is remarkably simple. For instance, the following command will run a Grails application with the production settings:

$ grails prod run-app

If you recall the output of the grails help command, you will remember that the basic usage of the grails command is as follows:

Usage (optionals marked with *):
grails [environment]* [target] [arguments]*

In other words, the first optional token after the grails executable is the environment, and three built-in options ship with Grails:

  • prod: The production environment settings. Grails executes in the most efficient manner possible, against all configured production settings.
  • test: The test environment settings. Grails executes in the most efficient manner possible, against all configured test settings.
  • dev: The development environment settings. Grails is run in development mode with tools and behavior (such as hot reloading) enabled to optimize developer productivity.

Of course, Grails is not limited to just three environments. You can specify your own custom environment by passing in a system property called grails.env to the grails command. For example:

grails -Dgrails.env=myenvironment test-app

Here you execute the Grails test cases using an environment called myenvironment. So all this environment switching is handy, but what does it mean in practical terms? For one thing, it allows you to configure different databases for different environments, as you'll see in the next section.

Configuring Data Sources

Armed with your newly acquired knowledge of environments and how to switch between them, you'll see the implications when you start configuring data sources. What initial configuration steps are required to get a Grails application up and running? None. That's right; you don't have to configure a thing.

Even configuring the data source is optional. If you don't configure it, Grails will start up with an in-memory HSQLDB database. This is highly advantageous to begin with, particularly in terms of testing, because you can start an application with a fresh set of data on each load.

However, since it is a pretty common requirement, we will delve into data sources because you'll certainly need to configure them; plus, they'll help you develop your knowledge of environments.

The DataSource.groovy File

When you create a Grails application, Grails automatically provides a grails-app/conf/ DataSource.groovy file that contains configuration for each environment (see Figure 2-11). You might find this convenient, because it means most of the work is done for you, but you might prefer to use another database such as MySQL rather than the provided HSQLDB database.

image

Figure 2-11. The DataSource.groovy file

Defining a data source is one area where the strength of the Java platform becomes apparent. Java's database connectivity technology, JDBC, is extremely mature, with drivers available for pretty much every database on the market. In fact, if a database provider does not deliver high-quality, stable JDBC drivers, its product is unlikely to be taken seriously in the marketplace.

A data-source definition is translated into a javax.sql.DataSource instance that supplies JDBC Connection objects. If you've used JDBC before, the process will be familiar, with the first step ensuring that the driver classes, normally packaged within a JAR archive, are available on the classpath.

The DataSource.groovy file contains some common configuration setup at the top of the data-source definition, an example of which is presented in Listing 2-20.

Listing 2-20. Common Data-Source Configuration

dataSource {
       pooled = true
       driverClassName = "org.hsqldb.jdbcDriver"
       username = "sa"
       password = ""
   }

The snippet indicates that by default you want a pooled data source using the HSQLDB driver with a username of "sa" and a blank password. You could apply defaults to several other settings. Here's a list of the settings that the DataSource.groovy file provides:

  • driverClassName: This is the class name of the JDBC driver.
  • username: This is the username used to establish a JDBC connection.
  • password: This is the password used to establish a JDBC connection.
  • url: This is the JDBC URL of the database.
  • dbCreate: This specifies whether to autogenerate the database from the domain model.
  • pooled: This specifies whether to use a pool of connections (it defaults to true).
  • configClass: This is the class that you use to configure Hibernate.
  • logSql: This setting enables SQL logging.
  • dialect: This is a string or class that represents the Hibernate dialect used to communicate with the database.

Now we get to the interesting bit. Following the global dataSource block, you'll see environment-specific settings for each known environment: development, test, and production. Listing 2-21 presents a shortened example of the environment-specific configuration.

Listing 2-21. Environment-Specific Data-Source Configuration

environments {
       development {
           dataSource {
               dbCreate = "create-drop"
               url = "jdbc:hsqldb:mem:devDB"
           }
       }
       test {
           ...
       }
       production {
           ...
       }
   }

You'll notice that by default the development environment is configured to use an in-memory HSQLDB, with the URL of the database being jdbc:hsqldb:mem:devDB. Also note the dbCreate setting, which allows you to configure how the database is autocreated.


Note Hibernate users will be familiar with the possible values because dbCreate relates directly to the hibernate.hbm2ddl.auto property.


The dbCreate setting of the development environment is configured as create-drop, which drops the database schema and re-creates it every time the Grails server is restarted. This setting can prove useful for testing because you start off with a clean set of data each time. The available settings for the dbCreate property are as follows:

  • create-drop: Drops and re-creates the database schema on each application load
  • create: Creates the database on application load
  • update: Creates and/or attempts an update to existing tables on application load
  • [blank]: Does nothing

The production and test environments both use update for dbCreate so that existing tables are not dropped, but created or updated automatically. You might find it necessary in some production environments to create your database schema manually. Or maybe creating your database schema is your DBA's responsibility. If either is the case, simply remove the dbCreate property altogether and Grails will do nothing, leaving this task in your or your colleague's hands.

Configuring a MySQL Database

Building on the knowledge you've gained in the previous section about configuring an alternative database, you're now going to learn how to set up MySQL with Grails. You're going to configure Grails to use MySQL within the production environment, and to achieve this you need to tell Grails how to communicate with MySQL. You're using JDBC, so this requires a suitable driver. You can download drivers from the MySQL web site at http://www.mysql.com.

In this book's examples, we'll be using version 5.1.6 of MySQL Connector/J. To configure the driver, drop the driver's JAR file into the lib directory of the gTunes application, as shown in Figure 2-12.

image

Figure 2-12. Adding the driver's JAR file to the application's lib directory

With the driver in place, the next thing to do is configure the Grails DataSource to use the settings defined by the driver's documentation. This is common practice with JDBC (and equivalent technologies on other platforms) and essentially requires the following information:

  • The driver class name
  • The URL of the database
  • The username to log in with
  • The password for the username

Currently the production DataSource is configured to use an HSQLDB database that persists to a file. Listing 2-22 shows the production-database configuration.

Listing 2-22. The Production Data-Source Configuration

production {
       dataSource {
           dbCreate = "update"
           url = "jdbc:hsqldb:file:prodDb;shutdown=true"
       }
   }

Notice that the remaining settings (username, password, driverClassName, and so on) are inherited from the global configuration, as shown in Listing 2-20. To configure MySQL correctly, you need to override a few of those defaults as well as change the database URL. Listing 2-23 presents an example of a typical MySQL setup.

Listing 2-23. MySQL Data-Source Configuration

production {
       dataSource {
           dbCreate = "update"
           url = "jdbc:mysql://localhost/gTunes"
           driverClassName = "com.mysql.jdbc.Driver"
           username = "root"
           password = ""
       }
   }

This setup assumes a MySQL server is running on the local machine, which has been set up with a blank root user password. Of course, a real production environment might have the database on a different machine and almost certainly with a more secure set of permissions. Also note that you must specify the name of the MySQL driver using the driverClassName setting.

Configuring a JNDI Data Source

Another common way to set up a production data source in Grails is to use a container-provided Java Naming and Directory Interface (JNDI) data source. This kind of setup is typical in corporate environments where the configuration of a data source is not up to you, but to the deployment team or network administrators.

Configuring a JNDI data source in Grails couldn't be simpler; specifying the JNDI name is the only requirement. Listing 2-24 shows a typical JNDI setup.

Listing 2-24. JNDI Data-Source Configuration

production {
       dataSource {
           jndiName = "java:comp/env/jdbc/gTunesDB"
       }
   }

Of course, this assumes that the work has been done to configure the deployment environment to supply the JNDI data source correctly. Configuring JNDI resources is typically container-specific, and we recommend that you review the documentation supplied with your container (such as Apache Tomcat) for instructions.

Supported Databases

Because Grails leverages Hibernate, it supports every database that Hibernate supports. And because Hibernate has become a de facto standard, it has been tried and tested against many different databases and versions.

As it stands, the core Hibernate team performs regular integration tests against the following database products:

  • DB2 7.1, 7.2, 8.1
  • HSQLDB
  • HypersonicSQL 1.61, 1.7.0, 1.7.2, 1.8
  • Microsoft SQL Server 2000
  • MySQL 3.23, 4.0, 4.1, 5.0
  • Oracle 8i, 9i, 10g
  • PostgreSQL 7.1.2, 7.2, 7.3, 7.4, 8.0, 8.1
  • SAP DB 7.3
  • Sybase 12.5 (jConnect 5.5)
  • TimesTen 5.1

In addition, although not included in the Hibernate QA team's testing processes, these database products come with community-led support:

  • Apache Derby
  • HP NonStop SQL/MX 2.0
  • Firebird 1.5 with JayBird 1.01
  • FrontBase
  • Informix
  • Ingres
  • InterBase 6.0.1
  • Mckoi SQL
  • PointBase Embedded 4.3
  • Progress 9
  • Microsoft Access 95, 97, 2000, XP, 2002, and 2003
  • Corel Paradox 3.0, 3.5, 4.x, 5.x, and 7.x to 11.x
  • A number of generic file formats including flat text, CSV, TSV, and fixed-length and variable-length binary files
  • XBase (any dBASE; Visual dBASE; SIx Driver; SoftC; CodeBase; Clipper; FoxBase; FoxPro; Visual Fox Pro 3.0, 5.0, 7.0, 8.0, 9.0, and 10.0; xHarbour; Halcyon; Apollo; GoldMine; or Borland Database Engine (BDE)-compatible database)
  • Microsoft Excel 5.0, 95, 97, 98, 2000, 2001, 2002, 2003, and 2004

A few, mostly older, database products that don't support JDBC metadata (which allows a database to expose information about itself) require you to specify the Hibernate dialect explicitly using the dialect property of the data-source definition. You can find available dialects in the org.hibernate.dialect package. You'll learn more about data-source definitions in future chapters, including Chapter 12. For now, since we have readied our application for the production environment, let's move on to the next step: deployment.

Deploying the Application

When you execute a Grails application using the run-app command, Grails configures the application to be reloaded upon changes at runtime, allowing quick iterative development. This configuration does, however, affect your application's performance. The run-app command is thus best suited for development only. For deployment onto a production system, you should use a packaged Web Application Archive (WAR) file. Doing this follows Java's mature deployment strategy and the separation of roles between developers and administrators.

As a significant added bonus, Grails' compliance with the WAR format means that IT production teams don't need to learn any new skills. The same application servers, hardware, profiling, and monitoring tools that you use with today's Java applications work with Grails, too.

Deployment with run-war

If you are satisfied with the built-in Jetty container as a deployment environment, you can quickly deploy your application by setting up Grails on your production environment and then checking out your Grails application from the version-control system you have locally. Once you've done this, simply type:

grails run-war

This command packages up Grails as a WAR file and then runs Jetty using the packaged WAR on port 8080. If you wish to change the port, you can follow the instructions in the "Step 6: Running the Application" section of Chapter 1.

As for the Jetty configuration itself, modifying the GRAILS_HOME/conf/webdefault.xml file can customize that.

Deployment with a WAR file

The run-war command is convenient, but you might want more control over your deployment environment. Or you might want to deploy onto another container, such as Apache Tomcat or BEA WebLogic, instead of Jetty.

What you need in these cases is a WAR file. The WAR file is the standardized mechanism for deployment in the Java world. Every Java EE–compliant web container supports the format. But some older containers might have quirks, so check out the http://grails.org/Deployment page on the wiki for helpful info on container-specific issues.

To create a WAR archive, use Grails' war command:

$ grails war

By default, if no environment is specified, Grails assumes use of the production environment for a WAR file. However, as with other commands, you can change the environment if needed. For example:

$ grails test war

Once you've run the command, a brand-new WAR file appears in the root of your project directory (see Figure 2-13).

image

Figure 2-13. The gTunes WAR file

If the root directory is not a convenient location for the WAR file, you can always change it by specifying the target WAR location as the last argument to the war command:

$ grails test war /path/to/deploy/gTunes.war

With the WAR file created, you just need to follow your container's deployment instructions (which might be as simple as dropping the file into a particular directory), and you're done. Notice how the WAR file includes a version number? Grails features built-in support for application versioning. You'll learn more about versioning and deployment in Chapter 12.

Summary

Wow, that was a lot of ground to cover. You generated a simple CRUD interface, configured a different data source, and produced a WAR file ready for deployment. You learned some of the basics about how controllers work in Grails and previewed what is to come with GORM, Grails' object-relational mapping layer.

You also played with Grails' support for running different environments and configured a MySQL database for production. All of this should have given you a solid grounding in the basics of working with Grails. However, so far we've only touched on concepts such as domain classes, controllers, and views without going into much detail. This is about to change as we plunge head first into the gory details of what makes Grails tick.

Starting with Chapter 3, we'll begin the in-depth tour of the concepts in Grails. As we do that, we'll begin to build out the gTunes application and transform it from the prototype it is now into a full-fledged, functional application.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset