To write Facelet tag libraries or JSF components and then tie those components to
a tag library in facelets requires alot of scaffolding code and setup. While there
are possible advantages for certain scenarios, it is often observed that the benefits
of so much configuration and scaffolding code (usually only beneficial for large
development teams) are not worth the cost in time and maintenance. In addition, development
time due to the need for so much rebuilding and redeployment makes component development very
cumbersom and unproductive.
Gracelet Libraries attempt to cut out most, if not all, of the configuration
and scaffolding code and get directly to component development. Also, it is very easy
to develop components, since hot reloading is enabled. Gracelet Libraries also
give you the ability to keep alot of common code right next to each other, such as
writing a compact phase listener hook right next to the component, or components, that
use it.
Each library must declare a namspace variable, which causes it to automatically be
available as a Facelet tag library (no .taglib.xml's to write!).
There are various components that you can easily write in a Gracelet Library as shown
in the following list:
Below the definition of all these types are some real library examples.
General Information About Libraries and Components
Variable resolution inside the closures is the same as mentioned in the previous section
about view scripts.
A gracelet library is detected by the convention of the last part of its name. If a file ending in
ComponentLibrary.groovy is found in the WEB-INF/gracelet/lib directory of your web application
it will be loaded as a gracelet library. When the source is loaded as a groovy file
it is hot loadable. Once you have a library developed but want to cut down on the compilation process
needed for .groovy files, you can compile that groovy file as a class. As long as the last part of the
class file is ComponentLibrary.class you can put it in any package you want, as long the jar has a
seam.properties file, it will be found.
All of the items defined in the library should be assigned to non-declared variables. That
means you should not use the 'def' keyword when defining a component of the library or the
namespace.
For instance, to define the namespace for your library, you simply do the following:
Another interesting point is that a library is an application singleton, so if you do define
variables locally you can access such in your closures to hold/manage application level/library specific state.
In order to define a component you will use the method defined below for each different type.
You simply pass a map of settings to the component in order to participate in component execution.
You only have to define the settings that you are interested in specifying.
When the parameter expects a closure, the closure can accept the values mentioned in each reference
table below for each type. Thos values are optional, so you do not have to declare that you accept
any of them if you do not need them.
As you will notice, most of the closures you can define are passed the gracelet UIComponent instance
as the first possible parameter. Each gracelet component has a support class that contians many
useful convenience methods for rendering and other such things. You can access the support class
via the support property of the component. The following is a list of methods that can be used when
accessing the support class:
Method
Purpose
void getActionURL()
Returns the URL needed for post backs, like forms.
void getBuilder()
Returns a new instance of a RendererMarkupBuilder for this component
void renderChildren()
Renders the children components of the Gracelet Component
String renderChildrenAsText()
Renders the children components and returns them as a string
void renderComponent(UIComponent,FacesContext)
Renders the specified component
void renderComponents(Class)
Renders the children of this component that are of the class passed or a sub class
The same as the previous method, but will search for the UIComponent passed
To facilitate definition, most components will allow you to specify an unnamed closure as
the last parameter passed. The closure marked in this color is the one
that will be the default closure to be defined in these cases.
To create a component of this type in a Gracelet Library, you use the Generic() method.
Generic components extend the UIComponentBase, and thus are truly generic. You can use them
when there is no other component type that fits your purpose.
To create a component of this type in a Gracelet Library, you use the Graphic() method.
Generic components extend the UIComponentBase, and thus are truly generic. You can use them
when there is no other component type that fits your purpose.
To create a component of this type in a Gracelet Library, you use the Command() method.
Command components extend the UICommand class, and thus are true command objects recognized
by the JSF system. You will need to take care of post back recognition and event queueing
in order for the action expression and listeners to be called.
To create a component of this type in a Gracelet Library, you use the Message() method.
Message components extend the UIMessage class, and thus are truly JSF message components.
You can use them for components that will display messages about a particular component.
To create a component of this type in a Gracelet Library, you use the TagHandler() method.
TagHandler components extend the facelet TagHandler class. A map can be accepted
by the apply closure as shown below. This contains the following values:
Name
Purpose
state
This is a map that is tied to this handler and can be used to hold state
ctx
This is the current FaceletContext
parent
This is the current UIComponent that the handler should apply to
tag
This is the Facelet Tag object that is associated with this handler
tagAttributes
This is meant to replace the 'attributes', 'attmap' and 'atthtml' below which will be deprecated in the future. This will provide easier and more standard access to facelets tag attributes. See javadoc for the class gracelets.api.library.GraceletTagHandlerAttributes class.
config
This is the Facelet TagConfig object that is associated with this handler
attributes
This is the TagAttributes object associated with this handler
attmap
This is a dynamic map that on each get() of a value will resolve the ValueExpression related to the tag
atthtml
This is a map of retreived values off the attmap that have names specified as valid html attributes names
To create a component of this type in a Gracelet Library, you use the ComponentHandler() method.
ComponentHandler components extend the facelet ComponentHandler class. This
can be used to do meta handling on an already existing component or it can be
used to do componentType interchanging, in other words, you could have the handler
create different components depending on the parameters or other factors.
To create a component of this type in a Gracelet Library, you use the Renderer() method.
Renderer components extend the Renderer class, and thus are true renderers. You can set
the renderer on all of the JSF Component types and reference the same variable that you
defined for the renderer.
One diference with Renderer definitions is that they do not translate to valid tags. Rather
you generally assign them directly to a component definition. (see real library examples below)
To create a component of this type in a Gracelet Library, you use the Converter() method.
Converter components allow a closure or a set of two closures to act as converters
for values sent and received to and from web post request, usually for input or output
components.
To create a component of this type in a Gracelet Library, you use the RenderKit() method.
RenderKit components extend the GraceletRenderKit class, and thus are true render kit objects recognized
by the JSF system. You only need to define the closures that you want to in order to participate in the
render kit implementation. NOTE: You can only define ONE render kit per gracelet component library.
In most cases the closure will be passed a default implementation so you can simply call that implementations methods
and add your own output/code around what it produces.
To create a component of this type in a Gracelet Library, you use the Phase() method.
Phases are really 'phase hook' objects that get registered with the Gracelet Phase Listener. This
allows you to create a "phase listener", per se. You can intercept all parts of the JSF
Request lifecycle.
As seen below, you simply pass two parameters to the Phase() method. First the phase
you want to participate in, and the second, a closure that is the actual code executed
on the desired phase. This closure can take 2 parameters, the first is the phase that is
is about to be/or has just executed and the second a boolean, if true it means this is
executing before the phase in questin and if false, it means this is executing after the
phase has completed.
To create a component of this type in a Gracelet Library, you use the ScriptBindings() method.
Would you like to have some binding automatically available to gracelet view scripts?
You can accomplish this via the ScriptBindings() method in a gracelet library.
The example below would provide a "pageCompiled" variable for all view scripts, which would
return a Date object representing when the page was last compiled. Obviously it is wise to
use some base library specific name so as not to conflict with gracelet bound variables and
other libraries.
The apply closure must return a Map<String,Object> that will be applied to the binding
of each and every view script. The resolve closure will allow lazy initlization, if you want to
resolve a variable that has failed all normal resolution methods, your closure will be called
with the name as the first parameter, and if you return a non-null value, that value will "stick"
for the duration of the binding in question.
Setting Name
Possible Parameters
apply
{ GraceletBinding -> ... }
resolve
{ String,GraceletBinding -> ... }
Examples
The following is a gracelet library that is comes with the gracelets jar: