Download
FAQ History |
![]() ![]() ![]() |
API
Search Feedback |
Creating Custom Component Classes
As explained in When to Use a Custom Component, a component class defines the state and behavior of a UI component. Some of the state information includes the component's type, identifier, and local value. Some of the behavior defined by the component class includes:
The
UIComponentBase
class defines the default behavior of a component class. All of the classes representing the standard components extend fromUIComponentBase
. These classes add their own behavior definitions, as your custom component class will do.Your custom component class needs to either extend
UIComponentBase
directly or extend a class representing one of the standard components. These classes are located in thejavax.faces.component
package and their names begin with UI.To decide whether you need to extend directly from
UIComponentBase
or from one of the standard component classes, consider what behavior you want your component to have. If one of the standard component classes defines most of the functionality you need, you should extend that class rather thanUIComponentBase
. For example, suppose you want to create an editable menu component. It makes sense to have this component extendUISelectOne
rather thanUIComponentBase
because you can reuse the behavior already defined inUISelectOne
. The only new functionality you need to define is that which makes the menu editable.The image map example has two component classes:
UIArea
andUIMap
. TheUIMap
component class extends the standard component,UICommand
. TheUIArea
class extends the standard component,UIOutput
.This following sections explain how to extend a standard component and how to implement the behavior for a component.
Extending From a Standard Component
Both
UIMap
andUIArea
extend from standard components. TheUIMap
class represents the component corresponding to themap
tag:The
UIArea
class represents the component corresponding to thearea
tag:The
UIMap
component has one or moreUIArea
components as children. Its behavior consists of:The
UIMap
class extends fromUICommand
becauseUIMap
generates anActionEvent
when a user clicks on the map. SinceUICommand
components already have the ability to generate this kind of event, it makes sense to extendUICommand
rather than redefining this functionality in a custom component extending fromUIComponentBase
.The
UIArea
component class extendsUIOutput
becauseUIArea
requires avalue
andvalueRef
attribute, which are already defined byUIOutput
.The
UIArea
component is bound to a model object that stores the shape and coordinates of the region of the image map. You'll see how all of this data is accessed through thevalueRef
expression in Performing Encoding. The behavior of theUIArea
component consists of:Although these tasks are actually performed by
AreaRenderer
, theUIArea
component class must delegate the tasks toAreaRenderer
. See Delegating Rendering to a Renderer for more information.The rest of these components' behavior is performed in its encoding and decoding methods. Performing Encoding and Performing Decoding explain how this behavior is implemented.
Performing Encoding
During the Render Response phase, the JavaServer Faces implementation processes the encoding methods of all components and their associated renderers in the tree. The encoding methods convert the current local value of the component into the corresponding markup that represents it in the response.
The
UIComponentBase
class defines a set of methods for rendering markup:encodeBegin
,encodeChildren
,encodeEnd
. If the component has child components, you might need to use more than one of these methods to render the component; otherwise, all rendering should be done inencodeEnd
.Since
UIMap
is a parent component ofUIArea
, thearea
tags must be rendered after the beginningmap
tag and before the endingmap
tag. To accomplish this, theUIMap
class renders the beginningmap
tag inencodeBegin
and the rest of themap
tag inencodeEnd
.The JavaServer Faces implementation will automatically invoke the
encodeEnd
method of theUIArea
component's renderer after it invokesUIMap
'sencodeBegin
method and before it invokesUIMap
'sencodeEnd
method. If a component needs to perform the rendering for its children, it does this in theencodeChildren
method.Here are the
encodeBegin
andencodeEnd
methods ofUIMap
:public void encodeBegin(FacesContext context) throws IOException { if (context == null) { System.out.println("Map: context is null"); throw new NullPointerException(); } ResponseWriter writer = context.getResponseWriter(); writer.write("<Map name=\""); writer.write(getComponentId()); writer.write("\">"); } public void encodeEnd(FacesContext context) throws IOException { if (context == null) { throw new NullPointerException(); } ResponseWriter writer = context.getResponseWriter(); writer.write( "<input type=\"hidden\" name=\"selectedArea\""); writer.write("\">"); writer.write("</Map>"); }Notice that
encodeBegin
renders only the beginningmap
tag. TheencodeEnd
method renders theinput
tag and the endingmap
tag.These methods first check if the
FacesContext
is null. TheFacesContext
contains all of the information associated with the current request.You also need a
ResponseWriter
, which you get from theFacesContext
. TheResponseWriter
writes out the markup to the current response.The rest of the method renders the markup to the
ResponseWriter
. This basically involves passing the HTML tags and attributes to theResponseWriter
as strings, retrieving the values of the component attributes, and passing these values to theResponseWriter
.The
id
attribute value is retrieved with thegetComponentId
method, which returns the component's unique identifier. The other attribute values are retrieved with thegetAttribute
method, which takes the name of the attribute.If you want your component to perform its own rendering but delegate to a Renderer if there is one, include the following lines in the encode method to check if there is a renderer associated with this component.
If there is a Renderer available, this method invokes the superclass'
encodeEnd
method, which does the work of finding the renderer. TheUIMap
class performs its own rendering so does not need to check for available renderers.In some custom component classes that extend standard components, you might need to implement additional methods besides
encodeEnd
. For example, if you need to retrieve the component's value from the request parameters--such as to update a model object--you also have to implement thedecode
method.Performing Decoding
During the Apply Request Values phase, the JavaServer Faces implementation processes the
decode
methods of all components in the tree. Thedecode
method extracts a component's local value from incoming request parameters and converts the value to a type acceptable to the component class.A custom component class needs to implement the decode method only if it must retrieve the local value, or it needs to queue events onto the
FacesContext
. TheUIMap
component must do both of the tasks. Here is the decode method ofUIMap
:public void decode(FacesContext context) throws IOException { if (context == null) { throw new NullPointerException(); } String value = context.getServletRequest().getParameter("selectedArea"); if (value != null) setAttribute("currentArea", value); context.addFacesEvent( new ActionEvent(this, commandName)); setValid(true); }The
decode
method first extracts the value ofselectedArea
from the request parameters. Then, it sets the value ofUIMap
'scurrentArea
attribute to the value ofselectedArea
. ThecurrentArea
attribute value indicates the currently-selected area.The
decode
method queues an action event onto theFacesContext
. In the JSP page, theaction_listener
tag nested inside themap
tag causes theImageMapEventHandler
to be registered on themap
component. This event handler will handle the queued event during the Apply Request Values phase, as explained in Handling Events for Custom Components.Finally, the
decode
method callssetValid(true)
to confirm that the local values are valid.
Download
FAQ History |
![]() ![]() ![]() |
API
Search Feedback |
All of the material in The Java(TM) Web Services Tutorial is copyright-protected and may not be published in other works without express written permission from Sun Microsystems.