When a request comes in for a JSF page (based off your web.xml configuration),
usually determined by the requested resource ending in the URL pattern you have setup
in your web.xml for the FacesServlet, Gracelets looks to see if there is a corresponding .groovy
file/view to handle the request. If there is, Gracelet's steps in and builds the JSF view off the view script.
So if you had a request URL like http://localhost:8080/index.jsf
and in the root of your web application there is a file called index.groovy,
Gracelets will detect that and intervene to allow the view script to build
the view. View scripts take precedence over normal XHTML source files, so if
in the example mentioned you also had a file called index.xhtml, it would get
ignored since index.groovy exists.
A view script normally builds a view by means of the use
of special Groovy Builder's. Each instance of these special Groovy Builders, or gracelet builders, represents
a Facelet tag library. Most of the common tag libraries are automatically available
to the view script, like the Facelet UI Tag Library, JSF Core Tag Library, JSF HTML
Tag Library. A special builder is also available to easily output normal XML/XHTML
markup.
The following is a complete list of the basic set of libraries and the bound variable
you can use to reference them:
Automatically available Tag Libraries Namespace Aliases
Bound Variable Name/Alias
Tag Library Namespace
Shipped with Gracelets
f
http://java.sun.com/jsf/core
Yes
g
http://gracelets/taglib
Yes
h
http://java.sun.com/jsf/html
Yes
jq
http://gracelets/jquery
Yes
u
http://java.sun.com/jsf/facelets
Yes
xh
http://www.w3.org/1999/xhtml
Yes
To clarify, what we mean by "automatically available" is that you simple do not
have to define the namespace in your gracelet script. What it does not mean is
that all these libraries are availabe simply by using Gracelets. Above, the libraries
that that say "Yes" under the "Shipped with Gracelets" column, truly are available
and ready to use libraries. But the ones that say no simply mean that if you have
those libraries on your classpath, you don't have to define the namespace in order
to use them, they are automatically ready to be used by simply using the variable
mentioned above. Also if you are using extensions or Gracelet Component Libraries
from a third party or that you have defined yourself, other automatically available
aliases can also be instantly available to your Gracelet views.
Everything you are used to accessing in XHTML scripts is available
via the builders. Instead of referencing the XML Namespace aliases you define at the top
of XHTML views you reference bound builders (if they do not have an automatic alias available)
in Gracelet views. Each method called on a particular bound builder is really a direct
call to make the tag that has the same name as the method call. The map of parameters
passed to the method call become the tag attributes. If you pass a single parameter as well
it will be automatically linked to the 'value' attribute.
Having these tag libraries automatically available to each view script means there
is much less namespace declarations as there is in normal XHTML source files. You will normally
only have to import other third party tag libraries that may not be made to work directly with
Gracelets view library aliases.
Comparing a XHTML source view file to a practically identical Gracelet view script
will help to understand this:
After declaring the mtl variable like above , all calls to the mtl variable will participate
in the view building process and use the tag library set referenced by the namespace.
So if the 'http://mytaglib/namespace' library mentioned above had a defined tag called
coolOutput, you could reference it like so:
Any attributes passed to the builder method call become tag attributes. So if the
tag mentioned above uses an attribute called style, you could define it
like so:
If you pass a single value somewhere in the method argument list, it will be
automatically wired to the 'value' attribute. So for example, if the coolOutput
tag accepted a 'value' attribute, you could specify it as follows:
At this point you might be wondering what other benefits there are to using Gracelets
other than avoiding alot of xml and namespace declarations.
Something that should be obvious is that you can now run arbitrary groovy/java code, maybe
complicated view logic, right inside the view, thus not having to put view logic code
inside of a controller bean, where many times it does not belong. This makes it as flexible
as JSP pages. So if you want to do some arbitrary loop and create multiple of the same tag
or even different tags depending on each loop values, you could do that without the use
of complicated tags and facelet handlers.
For example, you could do the following to generate a menu on some template:
This last example where we show the use of groovy code loops being used is somewhat of a
static-dynamic feature. Since view scripts are only ran once, the loop is only done once.
For some things, this is actually good, and efficient. This allows one to build static parts of
the page based off of some source in the system that does not change very often. This could be
like an enum, or a table that is rather static between deployments.
This may not be useful to many, but it is important to understand the difference between the
this type of 'dynamic' page and the dynamic features we will be considering next.
One feature of gracelets that allows your page to be more dynamic is the render {} tag, that allows you to write
render time code. With the render {} tag you can create truly dynamic parts of the view (each page access wil be dynamically rendered).
The following example is a redo of the previous example in order to make it dynamic every time the
page is rendered:
The above example shows the render {} tag accepting 1 closures, which is a renderer closure.
The renderer closure is a RENDER time closure. This means that it is ran every time the page is rendered/accessed.
This also means that you do not have access inside this closure to the builders mentioned above. Remember that
Facelets/Gracelets view building is done prior to the component tree rendering. So by the time this closure
is ran the component tree has already been constructed by Gracelets. To make rendering code alot more compact
and easier, a special builder is automatically available via the builder getter on the component. You can call it
as many times as you want to get a markup builder to easily produce XML compliant markup.
All methods called on the builder are translated into regular markup and sent to the ResponseWriter. With
this example our problem of being truly dynamic in the previous example has been solved.
Now, what about accessing all the tags that JSF and Facelets give us. Well a second closure
can contain the children of the render {} tag. The render {} tag can render its children as many times as it wants.
So if you wanted to use the JSF 'outputLink' tag instead of the regular XHTML 'a' tag, you could do
what is shown in the following example:
As can be seen in the above example, you can also accept three parameters for your renderer
closure. The first is the JSF UIComponent instance, the second is the FacesContext instance and the
third a quick reference to the attributes of the UIComponent.
The UIComponent instance has some special methods which make it easy to render the children
components. A method called renderChildren() can be called as many times as desired to have the
children defined in the second closure rendered.
With this last render {} tag example, we see that we can have truly dynamic pages that can be as dynamic
as is needed or desired.
EL, closures and variable resolution
Another powerful dynamic part of view scripts is the option to use closures extensively. These closures
make an otherwise static view script more dynamic. You may have noticed above that there
were some EL expressions used to reference certain beans. While this is perfectly fine, you could
actually use closures instead. For example in the first converted example above, on line 20, you could
do the following instead:
Here we are using a closure to provide the list of select items instead of EL, which means if we wanted
or needed to we could write the code to actually produce the list right here in the script. This is great
for prototyping or for production bug fixes. There is alot more to be seen in this regards, but at least this
begins to show how closures can take the place of EL expressions, which gives you the power to put any type of
arbitrary groovy code and thus make it much more powerful than the limited expression language.
You may be wondering about variable resolution at this point. In the above examples we have
referred to variables that were not directly declared, and we have even assigned values to them. This
manifests part of Gracelets Variable Context solution. When you reference from or assign to a variable
that has not been declared somewhere in your script, Gracelets tries to resolve it via the variable contexts (view, request, conversation, session, application)
Also a set of useful variables is available for accessing common parts of the JSF or Servlet environment, these are mentioned
in the Appendix : Variables.
When you reference a variable it will search each different context in ascending order. When you assign
to a variable that does not exist in any context, it will use the current scoped context (which can be set)
and which defaults to Conversation scope in the default implementation and when using the JBoss Seam
extension. Thus if you assign to a non-declared variable and that also does not
currently exist in any variable context, and you have not changed scope, it will "outject" as it were, the value
you set to the conversation scoped variable that you are assigning to. This allows you to interact with the
variable contexts without any need for declaration, dependancies or injection/outjection.
Thus in the code snippet above, where we reference the 'dummyList' variable, it will actually search the variable
context's and resolve it. Since variable contexts are tied to the JSF bean model as well and the basic Request, Session
and Application scoped framework in JSF, all managed beans and really anything that can be accessed in a regular EL
expression can be acessed as variables in your view script.
Together with the use of closures you can begin to develop very powerful solutions in a compact single view script.
You can easily create special value binding closures with a method that is automatically available to view scripts. This method is
called Value(). It takes two different argument sets as is listed below:
Value( { } )
Value(setter: {}, getter: {})
The first on can be used to reference beans similiar to in EL. Notice the following example:
In the above example, it makes the 'someProperty' property of the myBean bean the value binding
of the 'inputText' tag, it will make it possible for the inputText component to set and get the value
from the specified property.
In the next example, we see the second way you can define a value closure, which allows you to put
in special logic for getting and setting:
1 h.inputText(value:Value(getter:{ myBean.someProperty }, setter:{ myBean.someProperty = it })
In this example we achieve practically the same thing as the previous example, but we are using
two different closures for the two operations, getting and setting. We could put any code in there
doing special operations each time the value is retreive or set. More about this is covered in the
tutorial, in the Closure Bindings section
Instead of using regular EL or action bindings, you can use action closures. Notice this
in the following code:
Here we can call the someBean, which takes care of persistence, passing it the selectedEntity object. Then
we can take care of UI messages here instead of in the bean controller. Since the facesMessages bean is
directly available (with or without JBoss Seam extension) we can simply reference and call the add() method in order
to pop a faces message on the stack.
Tags and Templates
In reality there is little difference between Gracelet Pages and Gracelet Tags and Templates. Everything
mentioned above applies equally to Tags and Templates. Templates of course are normally stored in a directory
off the WEB-INF directory where they cannot be directly referenced as page. Tags are normally referenced
in a Facelet Tag Library definition file (a file ending in .taglib.xml, please see the
Facelets Developer Documentation for more information on the use
and definition of Tag Libraries). Just as you can specify an XHTML source
file in a Tag Library file, so you can reference a Gracelet Tag script. Below is a fragment from a Tag Library
where we define a Gracelet Tag script: