Reference Manual for Gracelets - 2.0.0.SP2SourceForge.net Logo
2.3 - Tutorial : Using Gracelet Builders
One main feature that allows gracelet scripts to be able to harness the large component set already existing in JSF and Facelets are Gracelet Builders. Any library already defined in a Facelets .taglib.xml file is accessible to a gracelet script.

To see a list of automatically available libraries refer to the Introduction : How it Works : View Scripts section.

In an attempt to avoid confusion, it is good to clarify the difference between a tag library and a builder, although sometimes we use the term interchangeably. A tag library is a Facelet tag library defined in XML in the .taglib.xml format or programatically defined like the core libraries are in Facelets. A gracelet builder represents a tag library, and is the proxy in gracelets that allows you to access all the power in the tag libraries. Since they are so closely related and these details are really transparent to the developer we will use both terms to refer to builders themselves.

For general xml markup, you use the "xh" bound builder. For example if you want to build a simple hello world page, but with proper xhtml, you could do the following:

Using xh, the XHTML builder
Toggle Line Numbers
1 xh.html { 
2      
3     head { title("Hello World Example") } 
4  
5     body { 
6         print { "Hello World @ " + new Date() } 
7     } 
8      
9 } 
Hello World Example - Mozilla Firefox
http://somesite/somepage.jsf
Hello World Example
Hello World ExampleHello World @ Sun Jan 17 21:24:02 MST 2010
One very important point with the markup builder, and really this is an easy "gotcha" in XHTML source files, is that markup is just markup. Thus many times when you expect JSF to consider markup tags as a child components you don't get what you would expect. The JSF Core facet tag is a good example. Notice the following two examples:

Incorrect Facet Definition
Toggle Line Numbers
1 h.dataTable(value: { someDataModel }) { 
2      
3     j.facet(name: "header") { 
4         xh.a(href: "http://somesite/somepage") { 
5             h.graphicImage(url: "someimg.png", style: "border: 0")  
6         } 
7     } 
8      
9 } 
Correct Facet Definition
Toggle Line Numbers
1 h.dataTable(value: { someDataModel }) { 
2      
3     j.facet(name: "header") { 
4         u.component { 
5             xh.a(href: "http://somesite/somepage") { 
6                 h.graphicImage(url: "someimg.png", style: "border: 0")  
7             } 
8         } 
9     } 
10      
11 } 
Since a JSF Core facet component requires that it be passed only 1 child component the first example is incorrect. Since markup tags are only markup and not container JSF components, the a and img tags called on the "xh" builder really get translated into 2 text components. 1 component for the text before the graphicImage component and 1 component for the text after it. In other words the markup is on the same level in the component tree as the graphic image even though in definition it appears to be a child. Thus in the second example we encapsulate them all in a true JSF component, in this case, the component tag of the Facelet UI tag library.

Tag Attributes

Builder tag attributes are similiar to the print() and println() statements in that if you pass a static value the attribute will always be the same, where as if you pass inline EL expressions or closure expressions the attribute values will now be dynamic.

The following two examples will demonstrate this:
Setting static attribute
Toggle Line Numbers
1 import java.text.SimpleDateFormat 
2  
3 def f = new SimpleDateFormat("D") 
4  
5 xh.html { 
6      
7     head {  
8         title("Hello World Example") 
9         style { 
10             print """ 
11                 .body_class1 { font-family: Tahoma; } 
12                 .body_class2 { font-family: "Times New Roman"; } 
13             """ 
14         } 
15     } 
16  
17     body { 
18         div(class: Integer.parseInt(f.format(new Date())) % 2 == 0 ? "body_class1" : "body_class2") { 
19             print { "Hello World @ " + new Date() } 
20         } 
21     } 
22      
23 } 
Hello World Example - Mozilla Firefox
http://somesite/somepage.jsf
Hello World Example
Hello World Example
Hello World @ Sun Jan 17 21:24:02 MST 2010
Setting attribute with closure expression
Toggle Line Numbers
1 import java.text.SimpleDateFormat 
2  
3 def f = new SimpleDateFormat("D") 
4  
5 xh.html { 
6      
7     head {  
8         title("Hello World Example") 
9         style { 
10             print """ 
11                 .body_class1 { font-family: Tahoma; } 
12                 .body_class2 { font-family: "Times New Roman"; } 
13             """ 
14         } 
15     } 
16  
17     body { 
18         div(class: { Integer.parseInt(f.format(new Date())) % 2 != 0 ? "body_class1" : "body_class2" }) { 
19             print { "Hello World @ " + new Date() } 
20         } 
21     } 
22      
23 } 
Hello World Example - Mozilla Firefox
http://somesite/somepage.jsf
Hello World Example
Hello World Example
Hello World @ Sun Jan 17 21:24:02 MST 2010
The only difference between the last two examples is that in the second one the class attribute is wrapped with curly braces ({ ... }), which turns it into a closure expression, and therefore is dynamic.

In the first example the attribute value is somewhat dynamic, but once the page is compiled it will always be the same, so it depends on when the first person loaded the page. While in the second one, using a closure expression makes this truly dynamic, it will constantly recalculate the attribute on each time the attribute value is requested.

Common Builders

The Facelet UI library (u), the JSF Core library (j) and the JSF Html library (h) are among the automatically imported and available libraries in gracelet scripts. The following example will use common builders to create a registration page:

Registration Page
Toggle Line Numbers
1 xh.html(docType: "transitional") { 
2     head {  
3         title("Example template using common builders") 
4         style("body { font-family: Tahoma; }") 
5     } 
6      
7     body { 
8          
9         h.form { 
10             xh.fieldset { 
11                 legend("Registration Form") 
12                 table (width: "100%") { 
13                     tr { td("First"); td {  
14                         h.inputText(value: Value({ regBean.first }), required: true) { 
15                             j.validateLength(maximum: 20) 
16                         } 
17                     } } 
18                     tr { td("Last"); td {  
19                         h.inputText(value: Value({ regBean.last }))  
20                     } } 
21                     tr { td("Address"); td {  
22                         h.inputText(value: Value({ regBean.address }))  
23                     } } 
24                     tr { td("City"); td {  
25                         h.inputText(value: Value({ regBean.city }))  
26                     } } 
27                     tr { td("State"); td {  
28                         h.inputText(value: Value({ regBean.state }))  
29                     } } 
30                     tr { td("Country"); td {  
31                         h.inputText(value: Value({ regBean.country }))  
32                     } } 
33                     tr { 
34                         td(colspan: 2, align: "right") { 
35                             h.commandButton("Cancel", immediate: true, action: "home") 
36                             h.commandButton("Signup", action: {  
37                                 someActionBean.signup() 
38                                 facesMessages.add("You have been signed up!") 
39                                 return "home" 
40                             }) 
41                         } 
42                     } 
43                 } 
44             } 
45         } 
46          
47     } 
48 } 
All the code in red is using the markup builder, this will simply output regular markup, in this case XHTML. One small detail is the docType attribute on the first tag called. This is an easier way of having the <!DOCTYPE ... specified on a page.

All the code in green is using the JSF Html builder, thus the form tag is really going to create a JSF HTML form component in the JSF tree. Next we see code in this color calling the inputText tag to create each input field on the form. We also see the commandButton tag used twice to create a "Cancel" and "Signup" buttons for the form.

On line 15 we see code in blue. This is using the JSF Core tag library to put a validator on the first input component making sure the length of the input as no more than 20 characters when submitted.

Finally the code on lines 37 to 39 is action code that will be executed when the Signup button is pushed and the form is submitted to the server. It calls the signup() method on the someActionBean bean available to the variable contexts. Then we add a faces message to tell the user that he has been signed up and finally return the "home" outcome which will direct the user to the home page.

One thing that may stand out is that you need to qualify what builder you want to use in order to have the right JSF component added to the view. However, if you are using the same builder for children tags you don't have to qualify the builder. Thus on line 1 we qualify the builder with "xh.", but on line 2 we don't need to put "xh." before the head tag since its parent is using the same builder.

Gracelet tag library/builder

Gracelet comes packaged with one tag library that is automatically available and imported into any script with the bound variable g. This library is small right now, but expect it to grow as needed and useful components that are really missing are discovered and designed. One component that is available already though is a sub page component. This allows one to define sub views inside of the gracelet page easily.

This can work well for list/edit views, where you want a list of items and then have a form to be able to edit them. With the subpages component, you can do both in a single view, with page-level navigation. The main component's value binding is used to maintain state about which sub page is to be decoded/rendered. You can set the value binding to a particular value, like in an action closure, in order to change the sub page. The following example will illustrate this:

Sub Page Navigation
Toggle Line Numbers
1 xh.html { 
2      
3     g.subpages( value: Value({ userManagerNav }) ) { 
4          
5         u.component(page: "list") { 
6              
7             h.dataTable(value: { userList }, var: "user") { 
8                 j.facet(name: "header") { print "User List" } 
9                  
10                 h.column { 
11                     j.facet(name: "header") { print "Username" } 
12                     print { user.username } 
13                 } 
14  
15                 h.column { 
16                     j.facet(name: "header") { print "Real Name" } 
17                     print { user.name } 
18                 } 
19  
20                 h.column { 
21                     j.facet(name: "header") { print "Options" } 
22                     h.commandLink(action: {  
23                         selectedUser = user 
24                         userManagerNav = "edit" 
25                     }) { 
26                         xh.img(src: "edit.png", border: 0, title: { "Edit User - $user.name" }) 
27                     } 
28                 } 
29             } 
30              
31         } 
32          
33         u.component(page: "edit") { 
34              
35             h.form { 
36                 print "Username: "; h.inputText(value: Value({ selectedUser.username })); xh.br() 
37                 print "Real Name: "; h.inputText(value: Value({ selectedUser.name })); xh.br() 
38                 print "Password: "; h.inputSecret(value: Value({ selectedUser.password })); xh.br() 
39                 xh.hr() 
40                 h.commandButton("Cancel", immediate: true, action: { userManagerNav = "list" }) 
41                 h.commandButton("Save Changes", action: { 
42                     someActionBean.saveUser(selectedUser) 
43                     facesMessages.add("User changes saved") 
44                     userManagerNav = "list" 
45                 }) 
46             } 
47              
48         } 
49          
50     } 
51      
52 } 

Conclusions about builders

On alot of gracelet pages you will be able to dive right into composing your page, not worrying about importing the common libraries that are usually imported to just about every script. You simply call the tag name on the library you want and that tag will be called to compose its part of the JSF view. Also, attributes can be static, semi-static or completely dynamic using closure expressions.