9 November 2014
CUSTOM
COMPONENTS
► Composite components limited to composing base jsf components
o Custom components are how all of the base components were written and many libraries of sophisticated components such as ADFfaces, iceFaces, primeFaces, etc.
o valuable
to see mechanics in order to get deep understanding of framework
► 2 of a components main responsibilities are
o Encode (generate markup)
o Decode
http requests
► Must subclass UIComponent (or subclass)
o UIOutput
o UIInput
o UICommand

► important categories of data managed by UIComponent p421-2
o list of child components
o map of facet components
o map of attributes
o collection of event listeners
1. All JSF custom components
extend basic component classes such as UIComponent or its main subclasses UIInput,
UIOutput, UICommand. Science of
Consciousness: The process of transcending
gives you the direct experience of how your Self is an extension of the most
basic level of awareness, pure consciousness.
Spinner demo—how to use the tag 423
xmlns:corejsf="http://corejsf.com">
…
#{msgs.monthPrompt}
<corejsf:spinner value="#{cardExpirationDate.month}" id="monthSpinner" minimum="1" maximum="12" size="3"/>
#{msgs.yearPrompt}
<corejsf:spinner value="#{cardExpirationDate.year}" id="yearSpinner" minimum="1900" maximum="2100" size="5"/>
Encoding: generating markup
► markup generated
<input name="spinnerForm:monthSpinner" value="12" size="3" />
<input type="submit" name="spinnerForm:monthSpinner.less" value="<" />
<input type="submit" name="spinnerForm:monthSpinner.more" value=">" />
► 3 methods, only 1 needed for spinner since no children
o encodeBegin
o encodeChildren
o encodeEnd
public void encodeBegin(FacesContext context) throws IOException {
ResponseWriter writer = context.getResponseWriter();
String clientId = getClientId(context);
encodeInputField(writer, clientId);
encodeDecrementButton(writer, clientId);
encodeIncrementButton(writer, clientId);
}
private void encodeInputField(ResponseWriter writer, String clientId) throws IOException {
writer.startElement("input", this);
writer.writeAttribute("name", clientId, null);
Object v = getValue();
if (v != null) writer.writeAttribute("value", v, "value");
Object size = getAttributes().get("size");
if (size != null) writer.writeAttribute("size", size, "size");
writer.endElement("input");
}
private void encodeDecrementButton(ResponseWriter writer, String clientId) throws IOException {
writer.startElement("input", this);
writer.writeAttribute("type", "submit", null);
writer.writeAttribute("name", clientId + LESS, null);
writer.writeAttribute("value", "<", "value");
writer.endElement("input");
}
private void encodeIncrementButton( …
2. All components must override the encode method to generate the HTML markup to be sent in the HTTP response to the browser. The framework calls this method on every component during the render response phase. Science of Consciousness: Encoding can be considered an outward stroke in which the JSF framework has supported an orderly response into activity—similar to the outward stroke of meditation in which your experience of quiet awareness supports orderly and successful activity.
Decoding: processing http request
public void decode(FacesContext context) {
Map<String, String> requestMap = context.getExternalContext().getRequestParameterMap();
/* get JSF generated component id */
String clientId = getClientId(context);
int increment;
/*
detect which button < or > was clicked
*/
if (requestMap.containsKey(clientId + MORE)) increment = 1;
else if (requestMap.containsKey(clientId + LESS)) increment = -1;
else increment = 0;
try {
/* get request value for this component */
int submittedValue = Integer.parseInt((String) requestMap.get(clientId));
int newValue = getIncrementedValue(submittedValue, increment);
setSubmittedValue("" + newValue); //make it a String
}
catch(NumberFormatException ex) {
// let the converter take care of bad input, but we still have
// to set the submitted value, or the converter won't have
// any input to deal with
setSubmittedValue((String) requestMap.get(clientId));
}
}
/* adds increment to value and takes into account min and
max */
private int getIncrementedValue(int submittedValue, int increment) {
Integer minimum = toInteger(getAttributes().get("minimum"));
Integer maximum = toInteger(getAttributes().get("maximum"));
int newValue = submittedValue + increment;
if ((minimum == null || newValue >= minimum.intValue()) &&
(maximum == null || newValue <= maximum.intValue()))
return newValue;
else
return submittedValue;
}
/* value of minimum or maximum attributes could be set as
String literal or by a value expression,
which might return a Number */
private static Integer toInteger(Object value) {
if (value == null) return null;
if (value instanceof Number) return ((Number) value).intValue();
if (value instanceof String) return Integer.parseInt((String) value);
throw new IllegalArgumentException("Cannot convert " + value);
}
3. All components must override the decode method to retrieve the input value for this component and save it as the method’s submittedValue. Decode is called by the framework on all components during the apply request values phase. Science of Consciousness: Decoding can be considered an inward stroke which integrates the request into the structure of the framework—similar to the inward stroke of meditation that integrates our awareness into the structure of silent non-changing structure of pure consciousness.
TLD 433-4
► Namespace
o E.g. xmlns:corejsf=http://corejsf.com
o Goes
on the jsf page using the component
► Name of tag and component type
o Type is an id that gets used with annotations
o Identifies the class than implements the component
@FacesComponent("com.corejsf.Spinner")
public class UISpinner extends UIInput {
private static final String MORE = ".more";
► Specify file location in web.xml p434
<context-param>
<param-name>javax.faces.FACELETS_LIBRARIES</param-name>
<param-value>/WEB-INF/corejsf.taglib.xml</param-value>
</context-param>
► Convention – file name ends in taglib.xml
corejsf.taglib.xml
<facelet-taglib … >
<namespace>http://corejsf.com</namespace>
<tag>
<tag-name>spinner</tag-name>
<component>
<component-type>com.corejsf.Spinner</component-type> <!- -for tag handler annotation- - >
</component>
</tag>
</facelet-taglib>