JSF Central - Inside Gracelets Part 1: An Introduction
JSF Central

 
 Home 
 
 Products 
 
 Articles & Books 
 
 Resources 
Inside Gracelets
 
Inside Gracelets Part 1: An Introduction
by Lewis Gass
20 Oct 2009 00:15 EDT

In the first article of this three part series, Lewis Gass introduces Gracelets, a relatively new technology that combines Java Server Faces (JSF)/Facelets with the power of Groovy. Gracelets harnesses powerful features in Groovy and provides a Domain Specific Language (DSL) for JSF, complementing Facelets and providing many new features and an extensible framework. In this article, Lewis explains some of Gracelets features and shows why the project was created.


Groovy is a very powerful and useful technology. Although it is not the best fit for every problem -- there are many situations in which Java is the right solution -- a lot of times Groovy is extremely useful and efficient. When you're developing web applications, JSF/Facelets is usually much easier to use than Java Server Pages (JSPs) and more in line with the MVC design pattern. However, component development, prototyping, and writing quick small applications are still cumbersome. That's where Groovy could help.

Gracelets was created to let you write Groovy web pages inside a JSF application and still have the power of the JSF component infrastructure and the Facelets template technology inside Groovy scripts. Many of the attractive features in Groovy found a logical and helpful place in Gracelets JSF development, making the project what it is today. Gracelets also goes further in an attempt to solve various obstacles that JSF developers confront with JSF 1.2, such as resource loading and component development.

An alternative to XHTML/XML

Along with the Unified Expression Language (EL), Facelets is a good web development solution. It has simplified JSF view and component development. It is very useful for Integrated Development Environment (IDE) tools and even helps when you write tags by hand. However, when all you want to do is write a simple solution to a problem, or you'd like to prototype a solution, Facelets is still somewhat cumbersome. While some developers use XHTML and IDE tools for this, they also may not be the best choice when you would like to simply write a working piece of an application with as little code as possible. Gracelets makes this possible by providing Groovy scripts as an alternative to XHTML views, tags, and components.

For example, let's look at an XHTML view and then its equivalent Gracelets view. Here's the XHMTL:

<html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html" xmlns:c="http://java.sun.com/jstl/core"> <head> <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" /> <title>Hello</title> </head> <body> <form id="helloForm" jsfc="h:form"> <h2> Hi. My name is Duke. I'm thinking of a number from #{UserNumberBean.minimum} to #{UserNumberBean.maximum}. Can you guess it? </h2> <img id="waveImage" src="wave.med.gif" /> <input type="text" jsfc="h:inputText" id="userNo" value="#{UserNumberBean.userNumber}" validator="#{UserNumberBean.validate}"/> <input type="submit" jsfc="h:commandButton" id="submit" action="success" value="Submit" /> <p/> <h:message showSummary="true" id="errors1" for="userNo"/> <p/> <c:forEach begin="1" end="4" varStatus="v"> #{view.viewId} #{v.index}<br/> </c:forEach> </form> </body> </html> And here's the equivalent Gracelet view: xh.html (showDocType: "true") { xh.head { xh.meta ("http-equiv": "Content-Type", content: "text/html; charset=iso-8859-1") xh.title("Hello") } xh.body { h.form (id: "helloForm") { xh.h2("Hi. My name is Duke. I'm thinking of a number from #{UserNumberBean.minimum} to #{UserNumberBean.maximum}. Can you guess it?") xh.img (id: "waveImage", src: "wave.med.gif") h.inputText (id: "userNo", value: "#{UserNumberBean.userNumber}", validator: "#{UserNumberBean.validate}") h.commandButton (id: "submit", action: "success", "Submit") xh.p () h.message (showSummary: "true", id: "errors1", for: "userNo") xh.p () (1..4).each { v -> println { "$view.viewId $v.index" } } } } }

As you can see in this example, Gracelets views utilize the well known Groovy Builder concept. A particular builder represents a Facelets or Gracelets component library. Each method call on the builder represents a tag and the parameters passed represent the attributes for that tag. This allows Gracelets to harness the huge investment developers and third party vendors have already made in Facelets tag libraries. Notice that the Gracelets view does not have to import common library namespaces, such as the JSF HTML Library, which are automatically available via the 'h' variable. The common JSF/Facelets libraries are automatically available via bound variables in the view script (and also component libraries). Also, custom libraries and third-party libraries can easily define an automatically bound variable in order to facilitate their use and remove the need for declaring namespaces in your views and component libraries.

An alternative to the Unified Expression Language

Gracelets makes heavy use of Groovy closures, to the point that you can do anything and more than you can do in Facelets without ever writing a single EL expression (although you can use EL if you'd like to with Gracelets). Groovy closures are like anonymous snippets of code that can be passed around and invoked by different parts of an application. This powerful feature allows you to define method expressions in practically any part of the application, including views, controllers, and libraries. You can write valid Java or Groovy code as a replacement for EL expressions inside your Gracelets view scripts, controllers, and component libraries, which can save you a lot of coding in an XHTML/Java backing bean. For instance, in the XHTML view above, you would have to write a JSF validator class and set it up in the faces-config.xml and in your Facelets taglib.xml. With Gracelets you can define it in a view with no need for an entire class definition, a taglib.xml, or specifying it in the faces-config.xml.

In the example above, we could replace the EL expression used to reference the JSF Validator, as is shown (highlighted) below:

xh.html (showDocType: "true") { head { meta ("http-equiv": "Content-Type", content: "text/html; charset=iso-8859-1") title("Hello") } body { h.form (id: "helloForm") { xh.h2( value: { "Hi. My name is Duke. I'm thinking of a number from $UserNumberBean.minimum to $UserNumberBean.maximum. Can you guess it?" }) xh.img (id: "waveImage", src: "wave.med.gif") h.inputText (id: "userNo", value: Value { UserNumberBean.userNumber }, validator: { ctx, cmp, val -> if (val < UserNumberBean.minimum || val > UserNumberBean.maximum) throw new RuntimeException(someMsgBundle.numberOutOfRange) }) h.commandButton (id: "submit", action: "success", "Submit") xh.p () h.message (showSummary: "true", id: "errors1", for: "userNo") xh.p () (1..4).each { v -> println { "$view.viewId $v.index" } } } } }

A single place for component development

Normally, JSF/Facelets component development requires many different configurations and XML artifacts. While JSF 2.0 will relieve some of this, in many cases Groovy still has lots to offer in the area of JSF component development, especially in-house project-specific component development. With Gracelets you can write as many Facelets tags and JSF components as you want in a single file, although you can use more than one file if it becomes too big to manage. Since you can use the Groovy Builders and closure expressions in these libraries, they become very concise small tag definitions. Also, if you need to make a change to a particular component or tag, you can do so, refresh the page, and see the changes without redeploying. Inside these libraries you can define the Facelets namespace the components belong to. You can even define an automatically imported alias that can be used inside your Gracelets view scripts, so you don't have to memorize any namespaces or import and manage them in each view.

We could define some common components from the examples above in a Gracelet Component Library, for example:

namespace = "http://my.company/taglib" alias = "myt" tpl = TagHandler { xh.html (showDocType: "true") { head { meta ("http-equiv": "Content-Type", content: "text/html; charset=iso-8859-1") title { print { title ? title : "Some Default Title" } } } body { u.insert() } } numberInput = TagHandler { ctx -> h.inputText (id: ctx.tagAttributes.getValue("id", "userNo"), value: ctx.tagAttributes.getLiteral("value"), validator: { ctx, cmp, val -> if (val < UserNumberBean.minimum || val > UserNumberBean.maximum) throw new RuntimeException(someMsgBundle.numberOutOfRange) }) }

We created two tags for our library, one called tpl and the other numberInput. The tpl tag is a Facelet template (similar to a user source tag) which we can use for our views. The other is a Facelet template used to encapsulate our number input text box with its validator. We also defined an alias for this library which allows us to simply reference the alias in our views without the need to reference a namespace. In these libraries you can create JSF components, Facelets tags and handlers, and also some Gracelets specific components, which will be covered in a following article.

Our view would then look like this:

myt.tpl (title: "Hello") { h.form (id: "helloForm") { xh.h2( value: { "Hi. My name is Duke. I'm thinking of a number from $UserNumberBean.minimum to $UserNumberBean.maximum. Can you guess it?" }) xh.img (id: "waveImage", src: "wave.med.gif") myt.numberInput(value: Value { UserNumberBean.userNumber }) h.commandButton (id: "submit", action: "success", "Submit") xh.p () h.message (showSummary: "true", id: "errors1", for: "userNo") xh.p () (1..4).each { v -> println { "$view.viewId $v.index" } } } }

Your contextual environment: A first class citizen

Since Gracelets views are really specialized Groovy scripts, they can interact with the contextual environment with ease, as shown in figure 1.

  Figure 1. Injection/outjection with your contextual environment simplified in Groovy.
Figure 1. Injection/outjection with your contextual environment simplified in Groovy.

Gracelets 1.3.x is tightly integrated with JBoss Seam and includes direct support for JBoss Seam's contexts (session, conversation, etc.) and factories (data models, select item lists, generic factories). In Gracelets 2.0.0 and on, these concepts have been abstracted and you can use Gracelets by itself without any other framework, such as JBoss Seam. This makes Gracelets more pluggable into environments that do not need or use JBoss Seam. There is an extension for JBoss Seam in Gracelets 2.0.0 and later, so you can still use JBoss Seam together with all of Gracelets features.

Dealing with your contextual environment

When writing Gracelets view scripts, controllers, and component libraries, you can inject and outject values by simply referring to a non-declared variable (a bound variable) or assigning to one, as can be seen in the examples above where we simply reference the UserNumberBean variable. Gracelets has a default context for outjecting (usually the conversation context). If you want to deal with another context directly, you can refer to it by its unique name and deal with it like a Java Map and assign/retrieve values into and out of that particular context.

Below we keep track of how many times the user has played the number game, directly referencing the session context using the 'timesPlayed' variable:

myt.tpl (title: "Hello") { h.form (id: "helloForm") { xh.h2( value: { "Hi. My name is Duke. I'm thinking of a number from $UserNumberBean.minimum to $UserNumberBean.maximum. Can you guess it?" }) xh.h2 { print { "You have played this game $timesPlayed times." } } xh.img (id: "waveImage", src: "wave.med.gif") myt.numberInput(value: Value { UserNumberBean.userNumber }) h.commandButton (id: "submit", action: { sessionContext.timesPlayed += 1 return "success" }, "Submit") xh.p () h.message (showSummary: "true", id: "errors1", for: "userNo") xh.p () (1..4).each { v -> println { "$view.viewId $v.index" } } } }

Factories simplified and everywhere

You can define a factory inside a view, a controller, or even a component library. You define it by simply passing a name, an optional scope (defaults to conversation), and a closure. You can generally write a nice Data Model factory on a single line, since even the persistence contexts and the like can easily become part of your contextual environment.

We could have defined the UserNumberBean using a factory right inside the view -- this could be accomplished as show below:

Factory("UserNumberBean", "session") { [minimum: 1, maximum: 10] } myt.tpl (title: "Hello") { h.form (id: "helloForm") { xh.h2( value: { "Hi. My name is Duke. I'm thinking of a number from $UserNumberBean.minimum to $UserNumberBean.maximum. Can you guess it?" }) xh.h2 { print { "You have played this game $timesPlayed times." } } xh.img (id: "waveImage", src: "wave.med.gif") myt.numberInput(value: Value { UserNumberBean.userNumber }) h.commandButton (id: "submit", action: { sessionContext.timesPlayed += 1 return "success" }, "Submit") xh.p () h.message (showSummary: "true", id: "errors1", for: "userNo") xh.p () (1..4).each { v -> println { "$view.viewId $v.index" } } } }

Conclusion

This first article summarizes some of the outstanding features Gracelets has to offer, such as Groovy instead of XHTML, closures instead of EL, and simplified component development. We have also seen how such alternatives can save time when hand writing views, developing components, and doing prototypes. Also, we can see the power of groovy builders and closures, which provide more flexibility and expressiveness when writing views, controllers and libraries with the Gracelets technology.

How do views, controllers, and component libraries interact? What examples, tools, and help are available for those interested in Gracelets? Stay tuned, as these and other questions will soon be answered in the two upcoming articles.

Resources



RSS feed(all feeds)

The Editor's Desk
Podcasts
Inside Facelets
In the Trenches

Site version 1.83  Report web site problems

Copyright (C) 2003-2015 Virtua, Inc. All Rights Reserved. Java, JavaServer Faces, and all Java-based marks are trademarks or registered trademarks of Oracle Corporation. in the United States and other countries. Virtua, Inc. is independent of Oracle Corporation. All other trademarks are the sole property of their respective owners.