Webcam Chat QuickBooks Advice international calling cards international phone cards
JavaBeat Certifications Certifications Kits Articles Tutorials Tips QNA Book Store Interview Questions SCJP 1.5 SCJP 1.6 SCWCD 5.0 SCBCD 5.0 SCEA SCJA Feeds
Kaspersky Anti-Virus 2011
Submit Your Blog Feedback Request Article Print Email

Grails 1.1 Web Application Development

Author : PacktPub
Topic : ruby books 
Pages :
Hibernate Books | Spring Books | JSF Books | Java Books
Title : Grails 1.1 Web Application Development
Publisher : PacktPub
Topic : ruby
Related : Hibernate, Spring, Struts, ejb
Javabeat : Tips, Java / J2EE Tutorials, Certifications

Grails 1.1 Web Application Development

The expectations of our users are increasing, and rightly so. The Internet is no longer the playground of geeks and nerds. Businesses use it to communicate with and support their customers; families use it to keep in touch while whole communities share their experiences with like-minded people. The democratization of the Internet has brought a new wave of software into the lives of people who would otherwise rarely use computers. The most successful of the new generation of web applications have not been written for the expert user, but for the casual user, focusing on ease of use. Web application development frameworks that focus on developer productivity have improved the ability of developers to respond to the demands of their users. Simpler and more intuitive frameworks have allowed the rapid development and refinement of new features.

Java web application development has something of a checkered history; simple isn't it. There may be more than one way to skin a cat, but there are almost infinite numbers of ways to build a Java web application. The options that are available are mind-boggling. Which database server to use? What about the application server? You also better choose an MVC framework while you're at it. Should you use a persistence framework, or hand code SQL statements? If you use an ORM framework, which one is best? Don't forget to choose a logging library. How should the project be laid out? Once you've finished making all these decisions, it's time to start on the configuration to get all of these disparate frameworks working together. Now, eventually you are ready to start coding! No wonder the latest and greatest web applications are built in PHP and Ruby on Rails.

Java still has a lot to offer. It is faster than most other languages that are used for web application development. It is an extremely mature platform, with lots of high quality libraries available. Moreover, its static, strong typing gives you less rope to hang yourself with. However, Java developers need to find technologies that deal with the common activities of web development. Sometimes we need a few choices taken away to help us focus on the problem at hand, creating great software that provides value to our users at less cost to the people paying the bills.

Grails does just this. It removes the need for reams of configuration through a convention-based approach that constrains developers in a healthy way. The decisions concerning project layout and which frameworks to use are removed. This leaves the developers free to use their creative talents for producing great software, rather than tweaking configuration files.

Throughout this book, you will learn how to build a web application using Grails and a number of key plug-ins. You will see that it is possible to achieve a great deal with very little code. Who knows, you may even rediscover your passion for web development on the Java platform!

What This Book Covers

Chapter 1 presents a short state of the nation of Java web development and makes the case for a framework like Grails. At the end of the chapter, we will install and create a Grails project.

Chapter 2 covers the use of Grails scaffolding to generate some simple pages to manage users and roles for our application.

Chapter 3 shows how to post messages, where we write the first basic functionality for the application by allowing users to post messages that can be shared with other users. This chapter introduces a number of basic concepts for Grails development including: controllers, validation, Groovy Server Pages (GSP), and Grails Object-Relational Mapping (GORM).

Chapter 4 covers an introduction to Groovy. Here we take a short break from the Grails framework to get a better understanding of the Groovy programming language. We will cover just enough of the language to be able to proceed through the rest of the book.

Chapter 5 shows how to use our first external plug-in to add authentication and authorization to the application.

Chapter 6 covers testing, where we introduce the different levels of automated testing that are available in the Grails framework. We see how to write, unit tests with new support for testing in Grails 1.1. We also cover integration tests, and install a functional testing plug-in.

Chapter 7 covers file sharing, where we allow users to share files through the application by introducing file uploads.

Chapter 8 covers some advanced querying techniques, using Hibernate criteria support in GORM, to implement file version history.

Chapter 9 introduces Grails services in more depth. We see how to extract logic from our controllers into services to keep the application maintainable.

Chapter 10 introduces more advanced GORM techniques, such as: persisting inheritance and performing polymorphic queries to enable tagging. We also delve into GSP a bit more by using templates to encapsulate view components.

Chapter 11 covers AJAX and RIA Frameworks—Where we improve the user experience with AJAX to allow users to edit tags in-line and use the RichUI plug-in to create tag clouds and perform auto suggestion when editing tags.

Chapter 12 shows us how to use the Searchable plug-in to add a search feature to our site in a matter of minutes. We also provide an RSS feed and a REST based API for managing messages.

Chapter 13 show us how to build our own plug-in, where we follow the example of the Grails plug-in community and extract our tagging code into a plug-in that we can use on future projects.

Chapter 14 shows how to package and deploy the application to a production ready for use in a production environment. We then discuss some next steps that may be worth investigating to handle real world situations.

Managing Content through Tagging

Over the last few chapters, we added the ability for our users to upload and share files with their teammates. As with messages, files are displayed on the home page in the order they are added to the system. Currently all messages and files are displayed on the home page. Over time, our home page is going to become rather large and unwieldy. We need a user's home page to show only the files and messages that they are interested in. To do this, users need to be able to tag their content.

We will implement a simple tagging solution, restructure the home page and then add some new pages to the application for viewing all of the messages and files.

The new Grails concepts that will be introduced in this chapter are:

  • Working with inheritance in the domain classes, and looking at which strategies GORM supports for persistence
  • Using polymorphic queries over a domain inheritance hierarchy
  • Encapsulating view-rendering logic in GSP templates
  • Manipulating collections with the Groovy collect and sort methods

Add basic tagging

Tagging is a loose, community-based way of categorizing content. It allows a group of people to categorize by consensus. Anyone is able to tag a piece of content. The more a tag is used, the more meaning it takes on and the more widely used it becomes. This categorization by consensus has been dubbed as folksonomy (http://en.wikipedia.org/wiki/Folksonomy) in recent times.

So let's get started by building our tagging support.

Tagging domain model

When implementing tagging in our system, we need to consider the following:

  • We must be able to have many tags in our system
  • We must be able to associate a single tag with many different files and messages
  • We need to make sure that new domain objects can be easily tagged without having to change the tagging logic
  • We want to know when a domain object was tagged

To satisfy these requirements, we need to create the following new domain classes:

  • Tag—to store the name of the tag. There is one instance of this class per unique tag name in the application.
  • Tagger—to store the relationship from domain objects to a tag. This allows us to store the date a tag was added to a domain object.

Let's create these domain classes and then write a test to prove that we can tag a message using this tagging structure.

The Tag class

We are going to separate the tagging classes out from our application domain classes. Create a folder under grails-app/domain called tagging. This is where we will put the domain model to implement tagging.

Our Tag class is extremely simple and holds only a name property:


	package tagging
	class Tag {
		String name
		static constrains = {
			name( blank: false )
		}
	}

The Tagger class

The next class that we are going to create is the Tagger class. In relational terms, this object represents a link table between a Tag and any other domain class. It is important that the relationship between tagged domain classes and the Tagger relationship class is unidirectional. By this, we mean the domain classes are allowed to know that they can be tagged, but tags do not know which domain classes can be tagged, otherwise every tagged domain class would need a special relationship class.

Create the Tagger class as a domain class in the tagging package as follows:


	package tagging
	class Tagger {
		Tag tag
		static constraints = {
			tag( nullable: false )
		}
	}

The basics of our tagging model are complete! We now need some logic to allow tags to be created. Create a new service class called TagService under grails-app/ services/tagging, as shown below:


	package tagging
		class TagService {
			boolean transactional = true
			def createTagRelationships(String spaceDelimitedTags) {
				return spaceDelimitedTags?.split(' ')?.collect { tagName ->
					createTagRelationship( tagName )
				}
			}
			def createTagRelationship(String tagName) {
				def tag = Tag.findByName(tagName)?:
				new Tag(name: tagName).save()
				return new Tagger( tag: tag )
			}

This service provides two utility methods to create new relationships by tag name or by a space delimited string of tag names. The important behavior of these two methods is that they do not allow duplicate tags to be created in the application. If a tag name already exists, the tag will be retrieved from the database and used as the tag in the relationship.

Notice that the createTagRelationships method is using the collect method to simplify what would normally take a few more lines of code to achieve. We did briefl y cover the collect method back in our introduction to Groovy in Chapter 4, but to reiterate: the collect method is dynamically added to any object that can be iterated over. For example, collections, arrays, strings and so on. It takes a closure as its argument and executes this closure for each item in the collection. The return value from each execution of the closure is added to a new collection that the collect method builds up and then returns once it has finished iterating the original collection.

In createTagRelationship, we are using another neat language feature of Groovy called the "Elvis operator". It is named so, as it looks like Elvis' hair style. This is a shorter version of the normal Java ternary operator. If the operand being checked is true then the checked operand will be returned as the default, otherwise the alternative operand will be used. So in our example:


	def tag = Tag.findByName(tagName) ?: new Tag(name: tagName).save()

If a tag can be found from the database then it is used, otherwise a new tag is created.

Tagging a message

The next step is to allow a message to be tagged. Write some integration tests to make sure the relationships are working before using tagging in the application.

In the folder test/integration/app, create the file TaggableIntegrationTests. groovy and add the following code:


	package app
	import tagging.Tag
	class TaggableIntegrationTest extends GroovyTestCase {
		User flancelot
		protected void setUp() {
			flancelot = User.findByUsername('flancelot')
			Tag.list().each { it.delete() }
			Message.list().each { it.delete() }
		}
	}

The code above sets up the test data needed to create messages and associate tags to messages. Remember that the flancelot user already exists because it was created by the BootStrap class.

The first test will determine that we can add tags to a message and then retrieve messages by tag. Add the following test method to your test class:


	void testCanRetrieveMessagesByTags() {
		Message message = new Message(user: flancelot, title: 'tagged',
			detail: "I've been tagged.").save(flush: true)
		Message secondMessage = new Message(user: flancelot,
			title: 'other tagged',
			detail: "I've been tagged.").save(flush: true)
		message.addTag('urgent')
		message.addTag('late')
		secondMessage.addTag('urgent')
		def taggedMessages = Message.withTag( 'urgent' )
		assertEquals(2, taggedMessages.size())
		assertEquals(2, Tag.list().size())
		def secondMessages = Message.withTag( 'late' )
		assertEquals(1, secondMessages.size())
		assertEquals(2, Tag.list().size())
	}

The test above does the following:

  • Creates two new messages
  • Adds the urgent tag to both messages
  • Adds the late tag to one message
  • Checks if we can retrieve both messages by using the urgent tag
  • Checks if only one message is returned for the late tag

Notice that the highlighted lines of code have not been implemented yet. To allow this test to pass, we need to add the following methods to the Message domain class:

  • addTag—instance method to allow a message to be tagged
  • withTag— class method to retrieve all messages with a particular tag

Add the following method to the Message class (don't forget to import tagging.Tagger):


	def addTag(String tagName) {
		tags = (tags)?:[]
		tags << tagService.createTagRelationship( tagName )
	}

This method simply delegates the creation of the tag relationship off to the TagService class, and then stores the relationship in the tags list.

Add the following method to the Message class that retrieves all messages with a given tag name:


	def static withTag(String tagName) {
		return Message.withCriteria {
			tags {
				tag {
					eq('name', tagName )
				}
			}
		}
	}

This method must be static on the Message class, as it is used to load message instances for a given tag. We do not want to have to instantiate a message before we can perform the search.

Before running the test, you will notice both of these new methods assume that there is a property on the Message class called tags. This has not yet been created. We need to create a one-to-many relationship from Message to Tagger that will allow messages to be tagged. We also need to inject the TagService into new instances of the Message class so the work for creating a new tag relationship can be delegated. Add the relationship to the Message class and inject TagService as shown below:


	class Message {
		def tagService
		static hasMany = [tags:Tagger]
		…
	}

Now we can run our tests by entering the following on the command line:


grails test-app

We should see some output in the command line similar to:


Running test app.TaggableTest...
			testCanRetrieveMessagesByTags...SUCCESS

Tagging a file

Now that we have implemented tagging for messages, we need to make tagging available for files.

Currently the logic for creating and fetching tags is in the Message domain class. We need to extract this logic so the File domain class can reuse it. It's time to look at how GORM supports inheritance.

Recommended Books

Submit Your Blog Feedback Request Article Print Email

Java / J2EE Tutorials

Spring Framework

Hibernate Framework

JSF Framework

Struts Framework

Java Server Pages(JSP)

Servlets

Java / J2EE Design Patterns

SCJP

SCEA


JavaBeat Website (2004-2009), India
javabeat | advertise | about us | useful resources
Copyright (2004 - 2009), JavaBeat