2. Using the Tutorial Examples 3. Getting Started with Web Applications 5. JavaServer Pages Technology 7. JavaServer Pages Standard Tag Library 10. JavaServer Faces Technology 11. Using JavaServer Faces Technology in JSP Pages 12. Developing with JavaServer Faces Technology 13. Creating Custom UI Components Determining Whether You Need a Custom Component or Renderer When to Use a Custom Component Component, Renderer, and Tag Combinations Understanding the Image Map Example Why Use JavaServer Faces Technology to Implement an Image Map? Understanding the Rendered HTML Summary of the Application Classes Steps for Creating a Custom Component Creating Custom Component Classes Specifying the Component Family Delegating Rendering to a Renderer Handling Events for Custom Components Creating the Component Tag Handler Setting Component Property Values Setting the Component Property Values Defining the Custom Component Tag in a Tag Library Descriptor 14. Configuring JavaServer Faces Applications 15. Internationalizing and Localizing Web Applications 16. Building Web Services with JAX-WS 17. Binding between XML Schema and Java Classes 19. SOAP with Attachments API for Java 21. Getting Started with Enterprise Beans 23. A Message-Driven Bean Example 24. Introduction to the Java Persistence API 25. Persistence in the Web Tier 26. Persistence in the EJB Tier 27. The Java Persistence Query Language 28. Introduction to Security in the Java EE Platform 29. Securing Java EE Applications 31. The Java Message Service API 32. Java EE Examples Using the JMS API 36. The Coffee Break Application | Creating Custom Component ClassesAs explained inWhen to Use a Custom Component, a component class defines the state and behavior ofa UI component. The state information includes the component’s type, identifier, and localvalue. The behavior defined by the component class includes the following:
TheUIComponentBase class defines the default behavior of a component class. All theclasses representing the standard components extend fromUIComponentBase. These classes add their own behaviordefinitions, as your custom component class will do. Your custom component class must either extendUIComponentBase directly or extend a class representingone of the standard components. These classes are located in thejavax.faces.component packageand their names begin withUI. If your custom component serves the same purpose as a standard component, youshould extend that standard component rather than directly extendUIComponentBase. For example,suppose you want to create an editable menu component. It makes sense tohave this component extendUISelectOne rather thanUIComponentBase because you can reuse thebehavior already defined inUISelectOne. The only new functionality you need to define isto make the menu editable. Whether you decide to have your component extendUIComponentBase or a standard component,you might also want your component to implement one or more of thesebehavioral interfaces:
If your component extendsUIComponentBase, it automatically implements onlyStateHolder. Because all componentsdirectly or indirectly extendUIComponentBase, they all implementStateHolder. If your component extends one of the other standard components, it might alsoimplement other behavioral interfaces in addition toStateHolder. If your component extendsUICommand,it automatically implementsActionSource2. If your component extendsUIOutput or one of thecomponent classes that extendUIOutput, it automatically implementsValueHolder. If your component extendsUIInput, it automatically implementsEditableValueHolder andValueHolder. See the JavaServer Faces APIJavadoc to find out what the other component classes implement. You can also make your component explicitly implement a behavioral interface that itdoesn’t already by virtue of extending a particular standard component. For example, ifyou have a component that extendsUIInput and you want it to fireaction events, you must make it explicitly implementActionSource2 because aUIInputcomponent doesn’t automatically implement this interface. The image map example has two component classes:AreaComponent andMapComponent. TheMapComponent class extendsUICommand and therefore implementsActionSource2, which means it can fireaction events when a user clicks on the map. TheAreaComponent classextends the standard componentUIOutput. TheMapComponent class represents the component corresponding to themap tag: <bookstore:map current="NAmericas" immediate="true" action="bookstore" actionListener="#{localeBean.chooseLocaleFromMap}">TheAreaComponent class represents the component corresponding to thearea tag: <bookstore:area value="#{NA}" onmouseover="/template/world_namer.jpg" onmouseout="/template/world.jpg" targetImage="mapImage" />MapComponent has one or moreAreaComponent instances as children. Its behavior consists ofthe following
The rendering of themap andinput tags is performed bytut-install/javaeetutorial5/examples/web/bookstore6/src/java/com/sun/bookstore6/renderers/MapRenderer.java, butMapComponent delegates this rendering toMapRenderer. AreaComponent is bound to a bean that stores the shape and coordinates ofthe region of the image map. You’ll see how all this data isaccessed through thevalue expression inCreating the Renderer Class. The behavior ofAreaComponent consists of thefollowing
Although these tasks are actually performed byAreaRenderer,AreaComponent must delegate thetasks toAreaRenderer. SeeDelegating Rendering to a Renderer for more information. The rest of this section describes the tasks thatMapComponent performs as wellas the encoding and decoding that it delegates toMapRenderer.Handling Events for Custom Components detailshowMapComponent handles events. Specifying the Component FamilyIf your custom component class delegates rendering, it needs to override thegetFamilymethod ofUIComponent to return the identifier of acomponent family, which is used torefer to a component or set of components that can be renderedby a renderer or set of renderers. The component family is used alongwith the renderer type to look up renderers that can render the component. BecauseMapComponent delegates its rendering, it overrides thegetFamily method: public String getFamily() { return ("Map");}The component family identifier,Map, must match that defined by thecomponent-family elementsincluded in the component and renderer configurations in the application configuration resource file.Registering a Custom Renderer with a Render Kitexplains how to define the component family in the renderer configuration.Registering a Custom Component explains howto define the component family in the component configuration. Performing EncodingDuring the render response phase, the JavaServer Faces implementation processes the encoding methodsof all components and their associated renderers in the view. The encoding methodsconvert the current local value of the component into the corresponding markup thatrepresents it in the response. TheUIComponentBase class defines a set of methods for rendering markup:encodeBegin,encodeChildren,andencodeEnd. If the component has child components, you might need to usemore than one of these methods to render the component; otherwise, all renderingshould be done inencodeEnd. BecauseMapComponent is a parent component ofAreaComponent, thearea tags must be renderedafter the beginningmap tag and before the endingmap tag. To accomplishthis, theMapRenderer class renders the beginningmap tag inencodeBegin and the restof themap tag inencodeEnd. The JavaServer Faces implementation automatically invokes theencodeEnd method ofAreaComponent’s rendererafter it invokesMapRenderer’sencodeBegin method and before it invokesMapRenderer’sencodeEnd method. If acomponent needs to perform the rendering for its children, it does this intheencodeChildren method. Here are theencodeBegin andencodeEnd methods ofMapRenderer: public void encodeBegin(FacesContext context, UIComponent component) throws IOException { if ((context == null)|| (component == null)){ throw new NullPointerException(); } MapComponent map = (MapComponent) component; ResponseWriter writer = context.getResponseWriter(); writer.startElement("map", map); writer.writeAttribute("name", map.getId(),"id");}public void encodeEnd(FacesContext context) throws IOException { if ((context == null) || (component == null)){ throw new NullPointerException(); } MapComponent map = (MapComponent) component; ResponseWriter writer = context.getResponseWriter(); writer.startElement("input", map); writer.writeAttribute("type", "hidden", null); writer.writeAttribute("name", getName(context,map), "clientId");( writer.endElement("input"); writer.endElement("map");}Notice thatencodeBegin renders only the beginningmap tag. TheencodeEnd methodrenders theinput tag and the endingmap tag. The encoding methods accept aUIComponent argument and aFacesContext argument. TheFacesContextinstance contains all the information associated with the current request. TheUIComponent argumentis the component that needs to be rendered. The rest of the method renders the markup to theResponseWriter instance, whichwrites out the markup to the current response. This basically involves passing theHTML tag names and attribute names to theResponseWriter instance as strings, retrieving thevalues of the component attributes, and passing these values to theResponseWriter instance. ThestartElement method takes aString (the name of the tag) and thecomponent to which the tag corresponds (in this case,map). (Passing this information totheResponseWriter instance helps design-time tools know which portions of the generated markupare related to which components.) After callingstartElement, you can callwriteAttribute to render the tag’s attributes. ThewriteAttributemethod takes the name of the attribute, its value, and the name ofa property or attribute of the containing component corresponding to the attribute. Thelast parameter can benull, and it won’t be rendered. Thename attribute value of themap tag is retrieved using thegetIdmethod ofUIComponent, which returns the component’s unique identifier. Thename attribute value ofthe input tag is retrieved using thegetName(FacesContext, UIComponent) method ofMapRenderer. If you want your component to perform its own rendering but delegate toa renderer if there is one, include the following lines in theencoding method to check whether there is a renderer associated with this component. if (getRendererType() != null) { super.encodeEnd(context); return;}If there is a renderer available, this method invokes the superclass’sencodeEndmethod, which does the work of finding the renderer. TheMapComponent classdelegates all rendering toMapRenderer, so it does not need to check foravailable renderers. In some custom component classes that extend standard components, you might need toimplement other methods in addition toencodeEnd. For example, if you need toretrieve the component’s value from the request parameters, you must also implement thedecode method. Performing DecodingDuring the apply request values phase, the JavaServer Faces implementation processes thedecodemethods of all components in the tree. Thedecode method extracts a component’s localvalue from incoming request parameters and uses aConverter class to convert thevalue to a type that is acceptable to the component class. A custom component class or its renderer must implement the decode method onlyif it must retrieve the local value or if it needs toqueue events. TheMapRenderer instance retrieves the local value of the hiddeninput fieldand sets thecurrent attribute to this value by using itsdecode method.ThesetCurrent method ofMapComponent queues the event by callingqueueEvent, passingin theAreaSelectedEvent instance generated byMapComponent. Here is the decode method ofMapRenderer: public void decode(FacesContext context, UIComponent component) { if ((context == null) || (component == null)) { throw new NullPointerException(); } MapComponent map = (MapComponent) component; String key = getName(context, map); String value = (String)context.getExternalContext(). getRequestParameterMap().get(key); if (value != null) map.setCurrent(value); }}Thedecode method first gets the name of the hiddeninput fieldby callinggetName(FacesContext, UIComponent). It then uses that name as the key to therequest parameter map to retrieve the current value of theinput field. Thisvalue represents the currently selected area. Finally, it sets the value of theMapComponent class’scurrent attribute to the value of theinput field. Enabling Component Properties to Accept ExpressionsNearly all the attributes of the standard JavaServer Faces tags can accept expressions,whether they are value expressions or method expressions. It is recommended that youalso enable your component attributes to accept expressions because this is what pageauthors expect, and it gives page authors much more flexibility when authoring theirpages. Creating the Component Tag Handler describes howMapTag, the tag handler for themap tag, sets the component’svalues when processing the tag. It does this by providing the following:
To retrieve the expression objects thatsetProperties stored, the component class must implementa method for each property that accesses the appropriate expression object, extracts thevalue from it and returns the value. BecauseMapComponent extendsUICommand, theUICommand class already does the work of gettingtheValueExpression andMethodExpression instances associated with each of the attributes that itsupports. However, if you have a custom component class that extendsUIComponentBase, youwill need to implement the methods that get theValueExpression andMethodExpressioninstances associated with those attributes that are enabled to accept expressions. For example,ifMapComponent extendedUIComponentBase instead ofUICommand, it would need to include amethod that gets theValueExpression instance for theimmediate attribute: public boolean isImmediate() { if (this.immediateSet) { return (this.immediate); } ValueExpression ve = getValueExpression("immediate"); if (ve != null) { Boolean value = (Boolean) ve.getValue( getFacesContext().getELContext()); return (value.booleanValue()); } else { return (this.immediate); }}The properties corresponding to the component attributes that accept method expressions must acceptand return aMethodExpression object. For example, ifMapComponent extendedUIComponentBase instead ofUICommand, it would need to provide anaction property that returns and acceptsaMethodExpression object: public MethodExpression getAction() { return (this.action);}public void setAction(MethodExpression action) { this.action = action;}Saving and Restoring StateBecause component classes implementStateHolder, they must implement thesaveState(FacesContext) andrestoreState(FacesContext, Object) methodsto help the JavaServer Faces implementation save and restore the state of componentsacross multiple requests. To save a set of values, you must implement thesaveState(FacesContext) method.This method is called during the render response phase, during which the stateof the response is saved for processing on subsequent requests. Here is themethod fromMapComponent: public Object saveState(FacesContext context) { Object values[] = new Object[2]; values[0] = super.saveState(context); values[1] = current; return (values);}This method initializes an array, which will hold the saved state. It nextsaves all of the state associated withMapComponent. A component that implementsStateHolder must also provide an implementation forrestoreState(FacesContext, Object),which restores the state of the component to that saved with thesaveState(FacesContext)method. TherestoreState(FacesContext, Object) method is called during the restore view phase, duringwhich the JavaServer Faces implementation checks whether there is any state that was savedduring the last render response phase and needs to be restored in preparationfor the next postback. Here is therestoreState(FacesContext, Object) method fromMapComponent: public void restoreState(FacesContext context, Object state) { Object values[] = (Object[]) state; super.restoreState(context, values[0]); current = (String) values[1];}This method takes aFacesContext and anObject instance, representing the array thatis holding the state for the component. This method sets the component’s propertiesto the values saved in theObject array. When you implement these methods in your component class, be sure to specifyin the deployment descriptor where you want the state to be saved: eitherclient or server. If state is saved on the client, the state ofthe entire view is rendered to a hidden field on the page. To specify where state is saved for a particular web application, you needto set thejavax.faces.STATE_SAVING_METHOD context parameter to either client or server in yourapplication’s deployment descriptor. SeeSaving and Restoring State for more information on specifying where state is savedin the deployment descriptor. Copyright © 2010, Oracle and/or its affiliates. All rights reserved.Legal Notices |