XForms-JSF tag library
Completing the XForms-JSF tag library
In this section, we will complete the XForms-JSF tag library and demonstrate the development of each JSF component in it.
In the previous section, we demonstrated the development
of xforms-jsf:model, xforms-jsf:commandButton,
and xforms-jsf:selectOneRadio components in detail.
Now, without going into too much detail, we will discuss the development
of the remaining components. We will only stick to the behavior and implementation specific
to the components we are developing.
The following components are XForms-JSF tag library components we will develop:
-
xforms-jsf:selectOneMenu -
xforms-jsf:selectOneListbox -
xforms-jsf:selectManyListbox -
xforms-jsf:selectManyCheckbox -
xforms-jsf:selectManyMenu -
xforms-jsf:inputText -
xforms-jsf:inputSecret -
xforms-jsf:inputTextarea
We will explain these components in detail shortly, but first, we'll give a brief description of each component. We'll also discuss the markup generated by the component and the expected interpretation by the XForms browser for the markup, how the JSP author uses the component in the JSP page, and the possible entries for the JSF tag in the TLD file. Finally, we'll discuss the implementation of the tag handler class associated with the tag. After the development of the tag handler class, we will implement the component class for the tag.
Implementing the xforms-jsf:selectOneMenu component
The xforms-jsf:selectOneMenu component is similar to
the xforms-jsf:selectOneRadio component we developed in
Implementing the xforms-jsf:selectOneRadio tag.
The only difference is in the graphical appearance of the components in the
XForms browser. The remaining features are the same as the
xforms-jsf:selectOneRadio tag.
In the case of the xforms-jsf:selectOneRadio tag,
each choice appears with a radio button, while the
xforms-jsf:selectOneMenu tag choices appear in a menu list.
The xforms-jsf:selectOneMenu component renders the
following markup:
<xforms:select1 ref="selectedColor" model="optModel"
appearance="minimal"
xmlns:xforms="http://www.w3.org/2002/xforms">
<xforms:label>Choose a Color</xforms:label>
<xforms:item>
<xforms:label>Red</xforms:label>
<xforms:value>Red</xforms:value>
</xforms:item>
<xforms:item>
<xforms:label>White</xforms:label>
<xforms:value>White</xforms:value>
</xforms:item>
</xforms:select1>
|
Notice the value of the appearance attribute in the
above markup ("minimal"). In the markup of xforms-jsf:selectOneRadio, the
value of the appearance attribute was "full."
In the XForms browser, the above markup looks like the following:
The JSP author codes the following elements to use the component in the JSP page:
<xforms-jsf:selectOneMenu value="#{dataStore.selectedColor}"
ref="selectedColor" model="optModel">
<f:selectItems value="#{dataStore.colorsList}"/>
</xforms-jsf:selectOneMenu>
|
The explanation of this JSP code is the same as for
the selectOneRadiotag in implementingthejsfselectoneradiotag.
Let's start implementing the selectOneMenu
tag.
The first step is to make an entry in the TLD file. The
entries in the TLD files are the same as for the selectOneRadio
tag. The only difference is between the entry in the name element and in the
tag-class element. Look at the TLD file for selectOneMenu:
<?xml version="1.0" encoding="ISO-8859-1" ?>
<taglib>
.....
<tag>
<name>selectOneMenu</name>
<tag-class>xforms_jsf.Select1MenuTag</tag-class>
<!-- remaining is same as listed for selectOneRadio -->
</tag>
<!-- other tag instances-->
</taglib>
|
In this TLD file, we mentioned that the tag-class
element contains the xforms_jsf.Select1MenuTag class.
We will implement this tag handler class.
Except for the appearance property of the component, most
of the features are the same as for selectOneRadio in implementingthejsfselectoneradiotag. We will extend
the Select1MenuTag class from
Select1RadioTag and override only the
setProperties() method. The following code shows the
implementation of the Select1MenuTag class:
public class Select1MenuTag extends Select1RadioTag{
public void setProperties(UIComponent component){
super.setProperties(component);
UISelect1 uis = (UISelect1)component;
uis.getAttributes().put("appearance", "minimal");
}//setProperties
}//Select1MenuTag
|
We first make a call to the same
method of its base class that will perform the default functionality of the
setProperties() method defined in the base class. Then we
override the appearance property of the component with the
"minimal" value.
The JSF component class we will associate with the
selectOneMenu is UISelect1. It is the same
component class we developed for the selectOneRadio component in
Implementing the UISelect1 component.
Implementing the xforms-jsf:selectOneListbox component
The behavior of the xforms-jsf:selectOneListbox tag is
similar to the xforms-jsf:selectOneRadio component
we developed in Implementing the xforms-jsf:selectOneRadio tag. The only difference is
in the graphical appearance of
the components in the browser. The remaining aspects are similar to the
xforms-jsf:selectOneRadio component. In the case of
xforms-jsf:selectOneRadio, each choice appears with a radio
button. In the case of xforms-jsf:selectOneMenu, the choices
appear in a list box.
The xforms-jsf:selectOneListbox component we are
going to implement renders the following markup:
<xforms:select1 ref="selectedColor" model="optModel"
appearance="compact" xmlns:xforms="http://www.w3.org/2002/xforms">
<xforms:label>Choose a Color</xforms:label>
<xforms:item>
<xforms:label>Red</xforms:label>
<xforms:value>Red</xforms:value>
</xforms:item>
<xforms:item>
<xforms:label>White</xforms:label>
<xforms:value>White</xforms:value>
</xforms:item>
</xforms:select1>
|
Notice the value of the appearance attribute in the
above markup ("compact"). In the markup of
xforms-jsf:selectOneRadio, the value of the
appearance attribute was "full."
In the XForms browser, the above markup looks like the following:
The JSP author codes the following elements to use the component in the JSP file:
<xforms-jsf:selectOneListbox value="#{dataStore.selectedColor}"
ref="selectedColor" model="optModel">
<f:selectItems value="#{dataStore.colorsList}"/>
</xforms-jsf:selectOneListbox>
|
The TLD file entry for the selectOneListbox tag is
similar to the selectOneRadio tag:
<tag> <name>selectOneListbox</name> <tag-class>xforms_jsf.Select1ListTag</tag-class> <!-- remaining is same as listed for selectOneRadio --> </tag> |
In the above TLD file entry, the tag-class element
contains the Select1ListTag class, which is the name of the tag handler
class for the selectOneListbox tag. We will now implement
the Select1ListTag class.
Like the selectOneMenu tag, the
selectOneListbox tag is
similar to the selectOneRadio tag, except for the
appearance property. We will extend the tag handler class for
selectOneListbox from Select1RadioTag, as we did earlier
for the selectOneMenu tag. The following code shows
the implementation of the Select1ListTag class:
public class Select1ListTag extends Select1RadioTag{
public void setProperties(UIComponent component){
super.setProperties(component);
UISelect1 uis = (UISelect1)component;
uis.getAttributes().put("appearance", "compact");
}//setProperties
}//Select1ListTag
|
The JSF component class we will associate with the
selectOneListbox is UISelect1. It is the same
class that we developed for the selectOneRadio component in
Implementing the UISelect1 component. There is no
need to develop a separate component class, as the behavior of both components
is the same.
Implementing the xforms-jsf:selectManyListbox component
The xforms-jsf:selectManyListbox component
provides users with an option to select multiple
choices from a list of given choices in a list box. It renders the
XForms select element's markup.
The xforms-jsf:selectManyListbox component renders
the following markup:
<xforms:select ref="selectedColors" model="optModel"
appearance="compact" xmlns:xforms="http://www.w3.org/2002/xforms">
<xforms:label>Choose a Color</xforms:label>
<xforms:item>
<xforms:label>Red</xforms:label>
<xforms:value>Red</xforms:value>
</xforms:item>
<xforms:item>
<xforms:label>White</xforms:label>
<xforms:value>White</xforms:value>
</xforms:item>
</xforms:select>
|
In the XForms browser, the above markup looks like this:
The JSP author codes the following elements to use the component in the JSP file:
<xforms-jsf:selectManyListbox ref="selectedColors" model="optModel"
value="#{dataStore.selectedColors}">
<f:selectItems value="#{dataStore.colorsList}"/>
</xforms-jsf:selectManyListbox>
|
The details of the attributes of this component are the same
as the xforms-jsf:selectOneRadio component in
Implementing the xforms-jsf:selectOneRadio tag.
The only difference is between the value attribute of
selectManyListbox. As we explained, that value
is used by the component to set or get the JavaBeans property. The property
that the JSP author passes in the value attribute for the
selectManyListbox tag should be an array of
the string object in the model bean (while in the case of the
selectOneRadio tag, it was simply a string type
property).
Now we will implement the selectManyListbox tag by making
an entry in the TLD file to declare it. The entry looks like this:
<?xml version="1.0" encoding="ISO-8859-1" ?>
<taglib>
......
<tag>
<name>selectManyListbox</name>
<tag-class>xforms_jsf.SelectListBoxTag</tag-class>
<!-- JSF Specific Attributes -->
<attribute>
<name>value</name>
<required>false</required>
<rtexprvalue> false </rtexprvalue>
</attribute>
<attribute>
<name>valueChangeListener</name>
<required>false</required>
<rtexprvalue> false </rtexprvalue>
</attribute>
<attribute>
<name>rendered</name>
<required>false</required>
<rtexprvalue> false </rtexprvalue>
</attribute>
<attribute>
<name>id</name>
<required>false</required>
<rtexprvalue> false </rtexprvalue>
</attribute>
<attribute>
<name>binding</name>
<required>false</required>
<rtexprvalue> false </rtexprvalue>
</attribute>
<attribute>
<name>immediate</name>
<required>false</required>
<rtexprvalue> false </rtexprvalue>
</attribute>
<attribute>
<name>required</name>
<required>false</required>
<rtexprvalue> false </rtexprvalue>
</attribute>
<!-- XForms Attributes -->
<attribute>
<name> model </name>
<required> false </required>
<rtexprvalue> false </rtexprvalue>
</attribute>
<attribute>
<name>label</name>
<required> false </required>
<rtexprvalue> false </rtexprvalue>
</attribute>
<attribute>
<name> navindex </name>
<required> false </required>
<rtexprvalue> false </rtexprvalue>
</attribute>
<attribute>
<name> accesskey </name>
<required>false </required>
<rtexprvalue> false </rtexprvalue>
</attribute>
<attribute>
<name> bind </name>
<required> false </required>
<rtexprvalue> false </rtexprvalue>
</attribute>
<attribute>
<name> ref </name>
<required> true </required>
<rtexprvalue> false </rtexprvalue>
</attribute>
<attribute>
<name> selection </name>
<required> false </required>
<rtexprvalue> false </rtexprvalue>
</attribute>
<attribute>
<name> incremental </name>
<required> false </required>
<rtexprvalue> false </rtexprvalue>
</attribute>
</tag>
<!-other tag instances-->
</taglib>
|
In the above TLD file, we mentioned the tag handler
xforms_jsf.SelectListBoxTag class in the
tag-class element. Now we will implement
the SelectListBoxTag class:
public class SelectListBoxTag extends UIComponentTag{
private String value = null;
private String required = null;
private String immediate = null;
private String valueChangeListener = null;
private String ref = null;
private String bind = null;
private String model = null;
private String label = null;
private String navindex = null;
private String accesskey = null;
private String selection = null;
private String incremental = null;
public String getRendererType(){
return null;
}
public String getComponentType(){
return "Select";
}
public void setValue(String valueRef) {
this.value = valueRef;
}
public void setRequired(String required) {
this.required = required;
}
public void setImmediate(String immediate) {
this.immediate = immediate;
}
public void setValueChangeListener(String valueChangeListener) {
this.valueChangeListener = valueChangeListener;
}
public void setRef(String ref) {
this.ref = ref;
}
public void setBind(String bind) {
this.bind = bind;
}
public void setModel(String model) {
this.model = model;
}
public void setLabel(String label) {
this.label = label;
}
public void setNavindex(String navindex) {
this.navindex = navindex;
}
public void setAccesskey(String accesskey) {
this.accesskey = accesskey;
}
public void setSelection(String selection) {
this.selection = selection;
}
public void setIncremental(String incremental) {
this.incremental = incremental;
}
public void setProperties(UIComponent component) {
super.setProperties(component);
UISelect uis = (UISelect)component;
FacesContext fc = FacesContext.getCurrentInstance();
Application app = fc.getApplication();
if(required != null){
if(UIComponentTag.isValueReference(required)){
ValueBinding vb = app.createValueBinding(required);
uis.setValueBinding("required", vb);
}
else{
boolean boolRequired = (new Boolean(required)).booleanValue();
uis.setRequired(boolRequired);
}
}
if(valueChangeListener != null){
if(UIComponentTag.isValueReference(valueChangeListener)) {
Class args[] = {
javax.faces.event.ValueChangeEvent.class
};
MethodBinding mb =
app.createMethodBinding(valueChangeListener, args);
uis.setValueChangeListener(mb);
}
}
if(immediate != null) {
if(UIComponentTag.isValueReference(immediate)) {
ValueBinding vb = app.createValueBinding(immediate);
uis.setValueBinding("immediate", vb);
}
else{
boolean boolImmediate =
(new Boolean(immediate)).booleanValue();
uis.setImmediate(boolImmediate);
}
}
if(value != null) {
if(UIComponentTag.isValueReference(value)) {
ValueBinding vb = app.createValueBinding(value);
uis.setValueBinding("value", vb);
}
uis.setValue(value);
}
if(ref != null)
uis.getAttributes().put("ref", ref);
if(bind != null)
uis.getAttributes().put("bind", bind);
if(label != null)
uis.getAttributes().put("label", label);
if(model != null)
uis.getAttributes().put("model", model);
if(navindex != null)
uis.getAttributes().put("navindex", navindex);
if(accesskey != null)
uis.getAttributes().put("accesskey", accesskey);
if(selection != null)
uis.getAttributes().put("selection", selection);
if(incremental != null)
uis.getAttributes().put("incremental", incremental);
uis.getAttributes().put("appearance", "compact");
}//setProperties
}//SelectListBoxTag
|
This code is exactly like the code used in Implementing the xforms-jsf:model component, so we won't explain it here.
Now we'll discuss the JSF component class associated with
the xforms-jsf:selectManyListbox tag.
UISelect is the component class we
will associate with the xforms-jsf:selectManyListbox tag.
The UISelect component is similar to the UISelect1
component discussed in Implementing the UISelect1 component.
We extended the UISelect class from
UISelect1, which is part of the JSF's HTML tag library.
The following code shows the methods in the UISelect class:
public class UISelect extends UISelect1{
public void encodeEnd(FacesContext fc)
throws IOException{
}
private String[] getNewValues(Document doc, String tag){
}
}//UISelect
|
The UISelect
class overrides the encodeEnd() method and implements a
new helper method named getNewValues().
The encodeEnd() method is similar to the same method in
the UISelect1 class, except that it renders a different
markup.
The getNewValues() helper method returns the values
selected by the user, after fetching from the XML request. We need this
method because the values selected by the user come as an array of
strings in which each individual string is separated from the other by a space.
The getNewValues() method parses the user's
data and returns it in the form of a String[].
The decode() method calls the getNewValues() method,
passing it the Document object (that contains the request)
and the name of the XML tag that wraps values selected by the user:
private String[] getNewValues(Document doc, String tag){
String[] newValues = null;
NodeList nl = doc.getElementsByTagName(tag);
if (nl != null){
Node tags = null;
int length = nl.getLength();
for(int i=0; i<length ; i++){
tags = nl.item(i);
NodeList children = tags.getChildNodes();
if (children == null)
break;
if(children.item(i) == null)
break;
String values = children.item(i).getNodeValue();
if(values == null)
break;
int spaceCounter = 0;
int j = -1;
while(true) {
j = values.indexOf(" ", j + 1);
if(j == -1){
spaceCounter++;
break;
}
else
spaceCounter++;
}
newValues = new String[spaceCounter];
int index = 0;
for(int k = 0 ; values.length() > 0 ; k++){
k = values.indexOf(" ");
if(k != -1){
newValues[index++] = values.substring(0,k);
values = values.substring(k+1);
}
else{
newValues[index] = values.substring(0);
break;
}
}//for(int k = 0 ; values.length() > 0 ; k++)
}//for(int i=0; i<length ; i++)
}//if (nl != null)
return newValues;
}//getNewValues
|
Notice the following points in this code:
- It retrieves the node (from the
Document) that wraps the new values.
- It retrieves the contents of the node fetched
in step 1 (the list of choices selected by the user).
- Because this component lets users select more than
one choice at a time, a space separates each choice in the
node fetched in step 2.
- The
getNewValues()method extracts each choice and places it in an array of string type, then returns the array.
Now look at the following code, which shows the decode method implementation:
public void decode(FacesContext fc) {
if(fc == null)
throw new NullPointerException();
String tag = null;
String[] newValue = null;
String ref = (String) getAttributes().get("ref");
String bind = (String) getAttributes().get("bind");
String clientId = getClientId(fc);
if(bind == null)
tag = ref;
else
tag = bind;
Document doc = (Document) getModelBeanObject
("#{incomingXMLInstanceRequest.DOMDocument}", fc);
if(doc != null) {
newValue = getNewValues(doc, tag);
}
if(newValue == null)
setSubmittedValue(new String[0]);
else
setSubmittedValue(newValue);
setValid(true);
}//decode
|
Now you can use this component with any JSF application after making an entry in the faces-config.xml file:
<component> <component-type>Select</component-type> <component-class>xforms_jsf.UISelect</component-class> </component> |
Implementing the xforms-jsf:selectManyCheckbox component
The behavior of the xforms-jsf:selectManyCheckbox component is similar to
selectManyListbox. The only difference is between the
appearances of both the components. This component provides users with an option to select one
or more check boxes from a list of check boxes (each check box represents
a choice).
The xforms-jsf:selectManyCheckbox tag renders
the following markup:
<xforms:select ref="selectedColors" model="optModel"
appearance="full" xmlns:xforms= "http://www.w3.org/2002/xforms">
<xforms:label>Choose a Color</xforms:label>
<xforms:item>
<xforms:label>Red</xforms:label>
<xforms:value>Red</xforms:value>
</xforms:item>
<xforms:item>
<xforms:label>White</xforms:label>
<xforms:value>White</xforms:value>
</xforms:item>
</xforms:select>
|
The only difference between the markups of
the xforms-jsf: selectManyCheckbox and
xforms-jsf:selectManyListbox tags is the
appearance attribute.
In the XForms browser, the above markup looks like the following:
The JSP author codes the following elements to use the tag in the JSP file:
<xforms-jsf:selectManyCheckbox ref="selectedColors"
value="#{dataStore.selectedColors}" model="optModel">
<f:selectItems value="#{dataStore.colorsList}"/>
</xforms-jsf:selectManyCheckbox>
|
Now let's start implementing the selectManyCheckbox tag.
Its TLD entry:
<tag> <name>selectManyCheckbox</name> <tag-class>xforms_jsf.SelectCheckListTag</tag-class> <!-- remaining is same as listed for selectManyListbox --> </tag> |
In the above TLD file, we mentioned
<tag-class>xforms_jsf.SelectCheckListTag</tag-class>. We will
implement this tag handler class.
As explained earlier, the
selectManyCheckbox and selectManyListbox
components are similar. The only
difference is the appearance of the components, which are
controlled by the appearance property of the component.
We extend the tag handler class for this
component from SelectListBoxTag, which is the tag handler
class for the selectManyListbox component (explained in the previous
section), and override the setProperties() method, which only sets the
appearance property for the component.
The following code shows the implementation of the
SelectCheckListTag class, which represents the
selectManyCheckbox tag:
public class SelectCheckListTag extends SelectListBoxTag{
public void setProperties(UIComponent component){
super.setProperties(component);
UISelect uis = (UISelect)component;
uis.getAttributes().put("appearance", "full");
}
}//SelectCheckListTag
|
In the setProperties() method,
we first make a call to the same method of its base class that performs the default
functionality of the setProperties() method defined in the base class,
then we override the appearance property of the component with "full."
The component class for this JSF tag is
UISelect, the same as for
selectManyListbox.
Implementing the xforms-jsf:selectManyMenu component
The xforms-jsf:selectManyMenu component provides users
with an option to select check boxes from a tree of check boxes (in the
tree, each node has a check box and a label. Each node represents a
choice).
The xforms-jsf:selectManyMenu component renders the following
markup:
<xforms:select ref="selectedColors" model="optModel"
appearance = "minimal"
xmlns:xforms="http://www.w3.org/2002/xforms">
<xforms:label>Choose a Color</xforms:label>
<xforms:item>
<xforms:label>Red</xforms:label>
<xforms:value>Red</xforms:value>
</xforms:item>
<xforms:item>
<xforms:label>White</xforms:label>
<xforms:value>White</xforms:value>
</xforms:item>
</xforms:select>
|
If you compare the markups generated by the
xforms-jsf:selectManyMenu and
xforms-jsf:selectManyListbox components,
you will see that the difference is only in the value of the
appearance attribute.
In the XForms browser, the above markup looks like the following:
The JSP author codes the following elements to use the component in the JSP file:
<xforms-jsf:selectManyMenu value="#{dataStore.selectedColors}"
ref="selectedColors" model="optModel">
<f:selectItems value="#{dataStore.colorsList}"/>
</xforms-jsf:selectManyMenu>
|
The TLD file entry for the selectManyMenu tag:
<tag> <name>selectManyCheckbox</name> <tag-class>xforms_jsf.SelectMenuTag</tag-class> <!-- remaining is same as listed for selectManyListbox --> </tag> |
In the above TLD file, we mentioned
<tag-class>xforms_jsf.SelectMenuTag</tag-class>.
Now we will implement this tag handler class.
The following code shows the implementation of the
SelectMenuTag class, which represents the
selectManyMenu tag:
public class SelectMenuTag extends SelectListBoxTag{
public void setProperties(UIComponent component){
super.setProperties(component);
UISelect uis = (UISelect)component;
uis.getAttributes().put("appearance", "minimal");
}
}//SelectMenuTag
|
In the setProperties() method, we first make a call to the same
method of its base class, which performs the default functionality of the
setProperties() method defined in the base class. We then override
the appearance property of the component with "minimal."
As before, we can use the UISelect component
class for this tag.
Implementing the xforms-jsf:inputText component
The xforms-jsf:inputText component provides the user
with an input box to enter text into it. In addition, xforms-jsf:inputText
renders the following markup:
<xforms:input ref="name" model="optModel" xmlns:xforms= "http://www.w3.org/2002/xforms"> <xforms:label>Name</xforms:label> <xforms:hint>Please enter your name.</xforms:hint> </xforms:input> |
In the above markup, the XForms hint element is used.
In the hint element, you can wrap a description about the text
to enter. For example, in the markup shown above, the label is "Name." When the user
rolls the mouse on the input box, the hint is displayed to the user.
In the XForms browser, the above markup looks like the following:
The JSP author codes the following elements to use the component in the JSP file:
<xforms-jsf:inputText value="#{customerData.name}" ref="name"
model="optModel">
</xforms-jsf:inputText>
|
The component saves the user data in the bean property
passed in the value attribute.
Let's start implementing the xforms-jsf:inputText
component. The first step is to make a new tag entry in the TLD file.
The tag entry in the TLD file for xforms-jsf:inputText looks
like the following:
<?xml version="1.0" encoding="ISO-8859-1" ?>
<taglib>
.....
<tag>
<name>inputText</name>
<tag-class>xforms_jsf.InputBoxTag</tag-class>
<!-- JSF Specific Attributes -->
<attribute>
<name>value</name>
<required>false</required>
<rtexprvalue> false </rtexprvalue>
</attribute>
<attribute>
<name>valueChangeListener</name>
<required>false</required>
<rtexprvalue> false </rtexprvalue>
</attribute>
<attribute>
<name>rendered</name>
<required>false</required>
<rtexprvalue> false </rtexprvalue>
</attribute>
<attribute>
<name>id</name>
<required>false</required>
<rtexprvalue> false </rtexprvalue>
</attribute>
<attribute>
<name>binding</name>
<required>false</required>
<rtexprvalue> false </rtexprvalue>
</attribute>
<attribute>
<name>immediate</name>
<required>false</required>
<rtexprvalue> false </rtexprvalue>
</attribute>
<attribute>
<name>required</name>
<required>false</required>
<rtexprvalue> false </rtexprvalue>
</attribute>
<!-- XForms Attributes -->
<attribute>
<name> model </name>
<required> false </required>
<rtexprvalue> false </rtexprvalue>
</attribute>
<attribute>
<name>label</name>
<required> false </required>
<rtexprvalue> false </rtexprvalue>
</attribute>
<attribute>
<name> navindex </name>
<required> false </required>
<rtexprvalue> false </rtexprvalue>
</attribute>
<attribute>
<name> accesskey </name>
<required>false </required>
<rtexprvalue> false </rtexprvalue>
</attribute>
<attribute>
<name> bind </name>
<required> false </required>
<rtexprvalue> false </rtexprvalue>
</attribute>
<attribute>
<name> hint </name>
<required> false </required>
<rtexprvalue> false </rtexprvalue>
</attribute>
<attribute>
<name> ref </name>
<required> true </required>
<rtexprvalue> false </rtexprvalue>
</attribute>
<attribute>
<name> inputmode </name>
<required> false </required>
<rtexprvalue> false </rtexprvalue>
</attribute>
<attribute>
<name> incremental </name>
<required> false </required>
<rtexprvalue> false </rtexprvalue>
</attribute>
<attribute>
<name> appearance </name>
<required> false </required>
<rtexprvalue> false </rtexprvalue>
</attribute>
</tag>
<!-other tag instances-->
</taglib>
|
In the above TLD file, we mentioned
<tag-class>xforms_jsf.InputBoxTag</tag-class>.
Now let's implement this tag handler class.
The following code shows the implementation of the
InputBoxTag class:
public class InputBoxTag extends UIComponentTag{
protected String value = null;
protected String required = null;
protected String immediate = null;
protected String valueChangeListener = null;
protected String ref = null;
protected String bind = null;
protected String hint = null;
protected String model = null;
protected String label = null;
protected String navindex = null;
protected String accesskey = null;
protected String inputmode = null;
protected String appearance = null;
protected String incremental = null;
public String getRendererType(){
return null;
}
public String getComponentType(){
return "InputBox";
}
public void setRef(String ref){
this.ref = ref;
}
public void setBind(String bind){
this.bind = bind;
}
public void setHint(String hint){
this.hint = hint;
}
public void setModel(String model){
this.model = model;
}
public void setLabel(String label){
this.label = label;
}
public void setValue(String valueRef){
this.value = valueRef;
}
public void setNavindex(String navindex){
this.navindex = navindex;
}
public void setAccesskey(String accesskey){
this.accesskey = accesskey;
}
public void setInputmode(String inputmode){
this.inputmode = inputmode;
}
public void setAppearance(String appearance){
this.appearance = appearance;
}
public void setIncremental(String incremental){
this.incremental = incremental;
}
public void setProperties(UIComponent component){
super.setProperties(component);
UIInputBox uib = (UIInputBox)component;
FacesContext fc = FacesContext.getCurrentInstance();
Application app = fc.getApplication();
if(required != null) {
if(UIComponentTag.isValueReference(required)) {
ValueBinding vb = app.createValueBinding(required);
uib.setValueBinding("required", vb);
}
else{
boolean boolRequired = (new Boolean(required)).booleanValue();
uib.setRequired(boolRequired);
}
}
if(valueChangeListener != null){
if(UIComponentTag.isValueReference(valueChangeListener)){
Class args[] = {
javax.faces.event.ValueChangeEvent.class
};
MethodBinding mb =
app.createMethodBinding(valueChangeListener, args);
uib.setValueChangeListener(mb);
}
}
if(immediate != null){
if(UIComponentTag.isValueReference(immediate)){
ValueBinding vb = app.createValueBinding(immediate);
uib.setValueBinding("immediate", vb);
}
else{
boolean boolImmediate =
(new Boolean(immediate)).booleanValue();
uib.setImmediate(boolImmediate);
}
}
if(value != null){
if(UIComponentTag.isValueReference(value)){
ValueBinding vb = app.createValueBinding(value);
uib.setValueBinding("value", vb);
}
else
uib.setValue(value);
}
if(ref != null)
uib.getAttributes().put("ref", ref);
if(bind != null)
uib.getAttributes().put("bind", bind);
if(hint != null)
uib.getAttributes().put("hint", hint);
if(label != null)
uib.getAttributes().put("label", label);
if(model != null)
uib.getAttributes().put("model", model);
if(navindex != null)
uib.getAttributes().put("navindex", navindex);
if(accesskey != null)
uib.getAttributes().put("accesskey", accesskey);
if(inputmode != null)
uib.getAttributes().put("inputmode", inputmode);
if(appearance != null)
uib.getAttributes().put("appearance", appearance);
if(incremental != null)
uib.getAttributes().put("incremental", incremental);
}//setProperties
}//InputBoxTag
|
Now let's implement the JSF component class associated
with xforms-jsf:inputText.
The UIInputBox is the component class we associate
with xforms-jsf:inputText. We extend
UIInputBox from UISelect1:
public class UIInputBox extends UISelect1{
public void encodeEnd(FacesContext fc) throws IOException{
if(fc == null)
throw new NullPointerException();
if(!isRendered())
return;
String ref = (String) getAttributes().get("ref");
String bind = (String) getAttributes().get("bind");
String hint = (String) getAttributes().get("hint");
String model = (String) getAttributes().get("model");
String label = (String) getAttributes().get("label");
String navindex = (String) getAttributes().get("navindex");
String inputmode = (String) getAttributes().get("inputmode");
String accesskey = (String) getAttributes().get("accesskey");
String appearance = (String) getAttributes().get("appearance");
String incremental = (String) getAttributes().get("incremental");
ResponseWriter out = fc.getResponseWriter();
out.write("<xforms:input ref=\"" + ref +"\"");
if(bind != null)
out.write(" bind=\""+ bind + "\"");
if(model != null)
out.write(" model=\""+ model + "\"");
if(navindex != null)
out.write(" navindex=\""+ navindex + "\"");
if(inputmode != null)
out.write(" inputmode=\""+ inputmode + "\"");
if(accesskey != null)
out.write(" accesskey=\""+ accesskey + "\"");
if(appearance != null)
out.write(" appearance=\""+ appearance + "\"");
if(incremental != null)
out.write(" incremental=\""+ incremental + "\"");
out.write(" xmlns:xforms=\"http://www.w3.org/2002/xforms\">");
if(label != null)
out.write("<xforms:label>" + label +
"</xforms:label>");
else
out.write("<xforms:label>" + "Enter data " +
"</xforms:label>");
if(hint != null)
out.write("<xforms:hint>" + hint + "</xforms:hint>");
out.write("</xforms:input>");
}//encodeEnd
}//UIInputBox
|
The UIInputBox
class only overrides the encodeEnd() method of the
UISelect1 class to render its own markup. The reason is because the markup
rendered is different from the parent class, but the behavior of the tag is not
different. It has to manage only one string coming from the user.
Now you can use this component with any JSF application after an entry in the faces-config.xml file:
<component> <component-type>InputBox</component-type> <component-class>xforms_jsf.UIInputBox</component-class> </component> |
Implementing the xforms-jsf:inputSecret component
The xforms-jsf:inputSecret component provides the user
with an input box to enter text in a nonreadable form.
The xforms-jsf:inputSecret renders the following
markup:
<xforms:secret ref="password" model="optModel" xmlns:xforms= "http://www.w3.org/2002/xforms"> <xforms:label>Password</xforms:label> <xforms:hint>Pls. Enter password here.</xforms:hint> </xforms:secret> |
In the XForms browser, the above markup looks like the following:
The JSP author codes the following elements to use the component in the JSP file.
<xforms-jsf:inputSecret value="#{customerData.pwd}" ref="password"
model="optModel">
</xforms-jsf:inputSecret>
|
The component saves the user's password in the bean
property passed in the value attribute.
The TLD file for xforms-jsf:inputSecret looks like the
following:
<tag> <name>inputSecret</name> <tag-class>xforms_jsf.InputSecretTag</tag-class> <!-- Remaining is same as implemented for inputText--> </tag> |
In the above TLD file, we mentioned
<tag-class>xforms_jsf.InputSecretTag</tag-class>.
Now let's implement this tag handler class.
Next, we'll implement the tag handler class for
xforms-jsf:inputSecret. The attributes for the
inputSecret tag are the same as were defined for the
inputText tag. We extended the
tag handler class for inputSecret from InputBoxTag that
is implemented for the inputText
tag in the previous topic. The following code shows the implementation of the
InputSecretTag class:
public class InputSecretTag extends InputBoxTag{
public String getComponentType(){
return "InputSecret";
}
public void setProperties(UIComponent component){
super.setProperties(component);
UIInputSecret uis = (UIInputSecret)component;
FacesContext fc = FacesContext.getCurrentInstance();
Application app = fc.getApplication();
if(required != null) {
if(UIComponentTag.isValueReference(required)) {
ValueBinding vb = app.createValueBinding(required);
uis.setValueBinding("required", vb);
}
else{
boolean boolRequired = (new Boolean(required)).booleanValue();
uis.setRequired(boolRequired);
}
}
if(valueChangeListener != null) {
if(UIComponentTag.isValueReference(valueChangeListener)){
Class args[] = {
javax.faces.event.ValueChangeEvent.class
};
MethodBinding mb =
app.createMethodBinding(valueChangeListener, args);
uis.setValueChangeListener(mb);
}
}
if(immediate != null) {
if(UIComponentTag.isValueReference(immediate)) {
ValueBinding vb = app.createValueBinding(immediate);
uis.setValueBinding("immediate", vb);
}
else{
boolean boolImmediate =
(new Boolean(immediate)).booleanValue();
uis.setImmediate(boolImmediate);
}
}
if(value != null) {
if(UIComponentTag.isValueReference(value)) {
ValueBinding vb = app.createValueBinding(value);
uis.setValueBinding("value", vb);
}
else
uis.setValue(value);
}
if(ref != null)
uis.getAttributes().put("ref", ref);
if(bind != null)
uis.getAttributes().put("bind", bind);
if(hint != null)
uis.getAttributes().put("hint", hint);
if(label != null)
uis.getAttributes().put("label", label);
if(model != null)
uis.getAttributes().put("model", model);
if(navindex != null)
uis.getAttributes().put("navindex", navindex);
if(accesskey != null)
uis.getAttributes().put("accesskey", accesskey);
if(inputmode != null)
uis.getAttributes().put("inputmode", inputmode);
if(appearance != null)
uis.getAttributes().put("appearance", appearance);
if(incremental != null)
uis.getAttributes().put("incremental", incremental);
}//setProperties
}//InputSecretTag
|
The InputSecretTag class overrides the
getComponentType() and setProperties() methods
of the InputBoxTag class. The getComponentType()
method returns the type of component associated with the xforms-jsf:inputSecret tag.
Now we will discuss the JSF component class associated
with xforms-jsf:inputSecret.
UIInputSecret is the component class we
associated with xforms-jsf:inputSecret. We extended
the UIInputSecret class
from the UIInputBox class:
public class UIInputSecret extends UIInputBox{
public void encodeEnd(FacesContext fc) throws IOException{
if(fc == null)
throw new NullPointerException();
if(!isRendered())
return;
String ref = (String) getAttribute("ref");
String bind = (String) getAttribute("bind");
String hint = (String) getAttribute("hint");
String model = (String) getAttribute("model");
String label = (String) getAttribute("label");
String navindex = (String) getAttribute("navindex");
String accesskey = (String) getAttribute("accesskey");
String inputmode = (String) getAttribute("inputmode");
String appearance = (String) getAttribute("appearance");
String incremental = (String) getAttribute("incremental");
ResponseWriter out = fc.getResponseWriter();
out.write("<xforms:secret ref=\"" + ref +"\"");
if(bind != null)
out.write(" bind=\""+ bind + "\"");
if(model != null)
out.write(" model=\""+ model + "\"");
if(navindex != null)
out.write(" navindex=\""+ navindex + "\"");
if(inputmode != null)
out.write(" inputmode=\""+ inputmode + "\"");
if(accesskey != null)
out.write(" accesskey=\""+ accesskey + "\"");
if(appearance != null)
out.write(" appearance=\""+ appearance + "\"");
if(incremental != null)
out.write(" incremental=\""+ incremental + "\"");
out.write(" xmlns:xforms=\"http://www.w3.org/2002/xforms\">");
if(label != null)
out.write("<xforms:label>" + label +
"</xforms:label>");
else
out.write("<xforms:label>"+"Enter Secret:"+
"</xforms:label>");
if(hint != null)
out.write("<xforms:hint>" + hint +
"</xforms:hint>");
out.write("</xforms:secret>");
}//encodeEnd
}//UIInputSecret
|
The UIInputSecret
class extends the UIInputBox class and overrides the
encodeEnd() method, which renders the markup for the XForms secret element.
After implementing the UIInputSecret class, you can use
this component with any JSF application after an entry in the
faces-config.xml file:
<component> <component-type>InputSecret</component-type> <component-class>xforms_jsf.UIInputSecret</component-class> </component> |
Implementing the xforms-jsf:inputTextarea component
The xforms-jsf:inputTextarea component provides the
user with an edit box to enter multiple lines of text and renders the following
markup:
<xforms:textarea ref="comments" model="optModel" xmlns:xforms= "http://www.w3.org/2002/xforms"> <xforms:label>Comments</xforms:label> <xforms:hint>Please enter your comments.</xforms:hint> </xforms:textarea> |
In the XForms browser, the above markup looks like the following:
The JSP author codes the following elements to use the component in the JSP page.
<xforms-jsf:inputTextarea value="#{customerData.comments}"
ref="comments" model="optModel">
</xforms-jsf:inputTextarea>
|
The component saves the text entered by the user in
the model bean property passed in the value attribute.
The TLD file entry for the xforms-jsf:inputTextarea tag
looks like the following markup:
<tag> <name>inputTextarea</name> <tag-class>xforms_jsf.InputTextAreaTag</tag-class> <!-- Remaining is same as implemented for inputText--> </tag> |
In the above TLD file, we mentioned
<tag-class>xforms_jsf.InputTextAreaTag</tag-class>.
Now let's implement this tag handler class.
The attributes for the inputTextarea tag are the same as
defined for inputText. We extended the
InputTextAreaTag tag handler class from the InputBoxTag class
implemented for the inputText tag. The following code shows the implementation of the
InputTextAreaTag class:
public class InputTextAreaTag extends InputBoxTag{
public void setProperties(UIComponent component){
super.setProperties(component);
UIInputTextArea uita = (UIInputTextArea)component;
FacesContext fc = FacesContext.getCurrentInstance();
Application app = fc.getApplication();
if(required != null) {
if(UIComponentTag.isValueReference(required)) {
ValueBinding vb = app.createValueBinding(required);
uita.setValueBinding("required", vb);
}
else{
boolean boolRequired = (new Boolean(required)).booleanValue();
uita.setRequired(boolRequired);
}
}
if(valueChangeListener != null) {
if(UIComponentTag.isValueReference(valueChangeListener)){
Class args[] = {
javax.faces.event.ValueChangeEvent.class
};
MethodBinding mb =
app.createMethodBinding(valueChangeListener, args);
uita.setValueChangeListener(mb);
}
}
if(immediate != null) {
if(UIComponentTag.isValueReference(immediate)) {
ValueBinding vb = app.createValueBinding(immediate);
uita.setValueBinding("immediate", vb);
}
else{
boolean boolImmediate =
(new Boolean(immediate)).booleanValue();
uita.setImmediate(boolImmediate);
}
}
if(value != null) {
if(UIComponentTag.isValueReference(value)) {
ValueBinding vb = app.createValueBinding(value);
uita.setValueBinding("value", vb);
}
else
uita.setValue(value);
}
if(ref != null)
uita.getAttributes().put("ref", ref);
if(bind != null)
uita.getAttributes().put("bind", bind);
if(hint != null)
uita.getAttributes().put("hint", hint);
if(label != null)
uita.getAttributes().put("label", label);
if(model != null)
uita.getAttributes().put("model", model);
if(navindex != null)
uita.getAttributes().put("navindex", navindex);
if(accesskey != null)
uita.getAttributes().put("accesskey", accesskey);
if(inputmode != null)
uita.getAttributes().put("inputmode", inputmode);
if(appearance != null)
uita.getAttributes().put("appearance", appearance);
if(incremental != null)
uita.getAttributes().put("incremental", incremental);
}//setProperties
}//InputTextAreaTag
|
Now let's discuss the UIInputTextArea component class
associated with xforms-jsf:inputTextarea:
public class UIInputTextArea extends UIInputBox{
public void encodeEnd(FacesContext fc) throws IOException{
if(fc == null)
throw new NullPointerException();
if(!isRendered())
return;
String ref = (String) getAttributes().get("ref");
String bind = (String) getAttributes().get("bind");
String hint = (String) getAttributes().get("hint");
String model = (String) getAttributes().get("model");
String label = (String) getAttributes().get("label");
String navindex = (String) getAttributes().get("navindex");
String inputmode = (String) getAttributes().get("inputmode");
String accesskey = (String) getAttributes().get("accesskey");
String appearance = (String) getAttributes().get("appearance");
String incremental = (String) getAttributes().get("incremental");
ResponseWriter out = fc.getResponseWriter();
out.write("<xforms:textarea ref=\"" + ref +"\"");
if(bind != null)
out.write(" bind=\""+ bind + "\"");
if(model != null)
out.write(" model=\""+ model + "\"");
if(navindex != null)
out.write(" navindex=\""+ navindex + "\"");
if(inputmode != null)
out.write(" inputmode=\""+ inputmode + "\"");
if(accesskey != null)
out.write(" accesskey=\""+ accesskey + "\"");
if(appearance != null)
out.write(" appearance=\""+ appearance + "\"");
if(incremental != null)
out.write(" incremental=\""+ incremental + "\"");
out.write(" xmlns:xforms=\"http://www.w3.org/2002/xforms\">");
if(label != null)
out.write("<xforms:label>" + label +
"</xforms:label>");
else
out.write("<xforms:label>"+" Enter Message
"+"</xforms:label>");
if(hint != null)
out.write("<xforms:hint>" + hint +
"</xforms:hint>");
out.write("</xforms:textarea>");
}//encodeEnd
}//UIInputTextArea
|
The UIInputTextArea
class extends the UIInputBox class. The
UIInputTextArea class only
overrides the encodeEnd() method, which renders the markup
for the XForms text area element.
The UIInputBox class renders a text box, which takes a
single line string as input. On the other hand, the
UIInputTextArea class
renders a text area, which can take multiple lines of text as input.
Whether it is a single line or a number of lines, it is always a string
(a multiple line string contains "\r" and "\n" characters at the end of
each line). We can treat both types of strings the same.
That's why the UIInputTextArea class does not
override the decode() method of the parent class.
Now we can use the UIInputTextArea component with any
JSF application after including the component entry in the faces-config.xml
file:
<component> <component-type>InputSecret</component-type> <component-class>xforms_jsf.UIInputSecret</component-class> </component> |
By implementing the UIInputTextArea component, our
XForms-JSF tab library is complete. In the next section, we will see
how to compile a tag library in a JAR file.
How to distribute tag libraries
To distribute a tag library, you have to compile its components in a JAR file. The JAR file (compiled tag library) should contain the following information:
- The compiled tag handler, component, and model
bean classes of a tag library in their respective packages
- The configuration files (faces-config.xml) and TLD file in a folder named META-INF
To create the JAR file, place the compiled classes and META-INF folder in a single folder (such as the XForms-JSF folder, which you will find when you unzip the section7.zip file; see Resources.
Run the following command in the command prompt:
d:\XForms-JSF>jar cvf xforms-jsf.jar *.* |
This command creates a JAR file named xforms-jsf.jar, which contains the META-INF folder (which in turn contains the TLD and configuration files) and the class files available in the XForms-JSF folder.
The xforms-JSF.jar file is available in the section7.zip file; see Resources.
Now the tag library is ready to be used with any JSF application. Place this JAR file in the WEB-INF\lib folder of your application. In the next section, we will develop a sample application to show you how to use the JAR file in a JSF application.
A sample JSP page to try the XForms-JSF tag library
To show how to use the tag library in an application, I have written a simple JSP page, which includes different components from our tag library:
<?xml version="1.0" encoding="iso-8859-1"?>
<html
xmlns:ev="http://www.w3.org/2001/xml-events"
xmlns:xforms="http://www.w3.org/2002/xforms">
<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %>
<%@ taglib uri=" http://afictitiousshoppingcart.com/XForms-JSF"
prefix="xforms-jsf" %>
<f:view>
<head>
<xforms-jsf:model value="#{customerData.model}"/>
</head>
<body>
<h1>Customer Information</h1>
<xforms-jsf:inputText ref="login" value="#{customerData.login}"
label="Login" hint="Please enter your login name."/>
<xforms-jsf:inputSecret ref="password"
value="#{customerData.password}"
label="Password" hint="Please enter your password."/>
<xforms-jsf:inputText ref="name" value="#{customerData.name}"
label="Name"
hint="Please enter your full name."/>
<xforms-jsf:textarea ref="address"
value="#{customerData.address}"
label="Mailing Address" hint="Please enter your address."/>
<xforms-jsf:commandButton label=" Finish ">
</xforms-jsf:commandButton>
</body>
</f:view>
</html>
|
The output of the above JSP page is shown in the following screenshot:
To try the XForms-JSF tag library and JSP page, unzip the section7.zip file in the source code download for this tutorial; see Resources.
The section7.zip file contains two folders named Demo1 and src, and a couple of files named xforms-jsf.jar and Demo1.war. The Demo1 folder contains the sample JSP page, and the src folder contains the complete source code for our XForms-JSF tag library we created in this section.
Now simply deploy the Demo1.war file in your application server. Be sure to use following URL in the address bar of your XForms browser:
http://localhost:8080/Demo1 |
As a result, the JSP page shown in the above screenshot displays in your XForms browser.



