Advanced Web Technologies 7) Create a new JSF Components Dr. E. - - PowerPoint PPT Presentation

advanced web technologies 7 create a new jsf components
SMART_READER_LITE
LIVE PREVIEW

Advanced Web Technologies 7) Create a new JSF Components Dr. E. - - PowerPoint PPT Presentation

Berner Fachhochschule-Technik und Informatik Advanced Web Technologies 7) Create a new JSF Components Dr. E. Benoist Fall Semester 09-10 Advanced Web Technologies 7) Create a new JSF Components 1 Writing new Components for JSF Motivations


slide-1
SLIDE 1

Berner Fachhochschule-Technik und Informatik

Advanced Web Technologies 7) Create a new JSF Components

  • Dr. E. Benoist

Fall Semester 09-10

Advanced Web Technologies 7) Create a new JSF Components 1

slide-2
SLIDE 2

Writing new Components for JSF

  • Motivations
  • Write a simple component

Extend a UIComponent Define the renderer Create a custom tag

  • A composite Component

Example of JSP file Subclass UIInput Creating a custom tag for FieldComponent The Renderer Mapping a renderer to a component

  • Conclusion

Advanced Web Technologies 7) Create a new JSF Components 2

slide-3
SLIDE 3

Need a Component?

◮ Use an existing

  • Text fields
  • Buttons
  • Tabbed Pannels

◮ Create your own new Component ◮ Import (or buy) an existing component

  • A special calendar for choosing a date
  • A field doing special validation client side,
  • . . .

Advanced Web Technologies 7) Create a new JSF Components Motivations 3

slide-4
SLIDE 4

JSF Component Model

◮ Much like Swing’s component model

  • It has events and properties
  • also has containers that contain components,
  • and that also are components that can be contained by other

containers.

  • In theory, the JSF component model is divorced from HTML

and JSP.

  • The standard set of components that ships with JSF has JSP

bindings and generates HTML renderings.

Component functionality typically centers around two actions: decoding and encoding data.

  • Decoding is the process of converting incoming request

parameters to the values of the component.

  • Encoding is converting the current values of the component

into the corresponding markup, that is, HTML.

Advanced Web Technologies 7) Create a new JSF Components Motivations 4

slide-5
SLIDE 5

Component and Renderer

◮ Two implementation approach

  • direct implementation, the component itself implements

decoding and encoding.

  • delegated implementation, the component delegates to a

renderer that does the encoding and decoding.

  • delegated implementation: you can associate your component

with different renderers that will represent it in different ways

  • n the page; for example a multi-select list box versus a list of

check boxes.

JSF components consist of two parts: the component and the renderer.

  • The JSF Component class defines the state and behavior of a

UI component;

  • a renderer defines how the component will be read from the

request and how it will be displayed – usually though HTML.

Advanced Web Technologies 7) Create a new JSF Components Motivations 5

slide-6
SLIDE 6

JSF lifecycle and JSF components

Advanced Web Technologies 7) Create a new JSF Components Motivations 6

slide-7
SLIDE 7

Further component concepts

◮ UIComponent is the base class for all JSF components.

  • When you develop your own components you will subclass

UIComponentBase,

  • it extends UIComponent,
  • default implementations for the abstract methods in

UIComponent.

◮ Components:

  • have parents and identifiers.
  • They are associated with a component type, (for registring in

faces-config.xml)

  • You can use the JSF-EL (expression language) to bind JSF

components to managed bean properties.

◮ A component can be a ValueHolder or an

EditableValueHolder.

◮ Components like form field components have a

ValueBinding that must be bound to a JavaBean read-write property.

Advanced Web Technologies 7) Create a new JSF Components Motivations 7

slide-8
SLIDE 8

Hello World, JSF style!

◮ Example: render tag <label>Form Test</label>

  • 1. Extend a UIComponent

◮ Create a class that extends UIComponent ◮ Save the component state ◮ Register the component with faces-config.xml

  • 2. Define the renderer or implement inline

◮ Override encode ◮ Override decode ◮ Register the renderer with faces-config.xml

  • 3. Create a custom tag that subclasses UIComponentTag

◮ Return the renderer type ◮ Return the component type ◮ Set up properties that might use JSF expressions Advanced Web Technologies 7) Create a new JSF Components Write a simple component 8

slide-9
SLIDE 9

Label Rendering example

◮ Creating a component ◮ Directly implementing a renderer ◮ Encoding output ◮ Associating a custom tag with a component

Advanced Web Technologies 7) Create a new JSF Components Write a simple component 9

slide-10
SLIDE 10

Using a JSF tag in a JSP

Advanced Web Technologies 7) Create a new JSF Components Write a simple component 10

slide-11
SLIDE 11

Step 1: Extend a UIComponent

import java.io.IOException; import javax.faces.component.UIOutput; import javax.faces.context.FacesContext; import javax.faces.context.ResponseWriter; public class LabelComponent extends UIOutput{ private String label; public String getLabel() { return label; } public void setLabel(String label) { this.label = label; } ...

Advanced Web Technologies 7) Create a new JSF Components Write a simple component: Extend a UIComponent 11

slide-12
SLIDE 12

Extend a UIComponent (Cont.)

JSF does the actual storage and state management, typically though a session, a hidden form field, cookies, etc. (This is usually a setting that you configure.). @Override public Object saveState(FacesContext context) { Object values[] = new Object[2]; values[0] = super.saveState(context); values[1] = label; return ((Object) (values)); } @Override public void restoreState(FacesContext context, Object state) { Object values[] = (Object[])state; super.restoreState(context, values[0]); label = (String)values[1]; }

Advanced Web Technologies 7) Create a new JSF Components Write a simple component: Extend a UIComponent 12

slide-13
SLIDE 13

Extend a UIComponent (Cont.)

The final step of creating the component is to register it with the faces-config.xml, as shown below: <faces−config> <component> <component−type>simple.Label</component−type> <component−class> arcmind.simple.LabelComponent </component−class> </component> ...

Advanced Web Technologies 7) Create a new JSF Components Write a simple component: Extend a UIComponent 13

slide-14
SLIDE 14

Step 2: Define the renderer

◮ Encode the component output

public class LabelComponent extends UIOutput{ ... public void encodeBegin(FacesContext context) throws IOException { ResponseWriter writer = context.getResponseWriter(); writer.startElement(”label”, this); writer.write(label); writer.endElement(”label”); writer.flush(); } ... }

Advanced Web Technologies 7) Create a new JSF Components Write a simple component: Define the renderer 14

slide-15
SLIDE 15

Define the renderer (Cont.)

◮ The family property shown below is used to associate

the Label component with a renderer. public class LabelComponent extends UIOutput{ ... public String getFamily(){ return ”simple.Label”; } ... }

Advanced Web Technologies 7) Create a new JSF Components Write a simple component: Define the renderer 15

slide-16
SLIDE 16

A side step: Hacking the JSF-RI

◮ f you’re using the JSF reference implementation from

Sun Microsystems (and not the MyFaces implementation), you’ll have to add the following to your component-creation code: public void encodeEnd(FacesContext context) throws IOException { return; } public void decode(FacesContext context) { return; }

Advanced Web Technologies 7) Create a new JSF Components Write a simple component: Define the renderer 16

slide-17
SLIDE 17

Step 3: Create a custom tag

◮ Bridging JSF and JSP

Advanced Web Technologies 7) Create a new JSF Components Write a simple component: Create a custom tag 17

slide-18
SLIDE 18

Create a custom tag (Cont.)

[LabelTag.java] public class LabelTag extends UIComponentTag { ... protected void setProperties(UIComponent component) { /∗ you have to call the super class ∗/ super.setProperties(component); ((LabelComponent)component).setLabel(label); }

Advanced Web Technologies 7) Create a new JSF Components Write a simple component: Create a custom tag 18

slide-19
SLIDE 19

Binding JSF and JSP

Advanced Web Technologies 7) Create a new JSF Components Write a simple component: Create a custom tag 19

slide-20
SLIDE 20

Registering a custom tag

[arcmind.tld] <taglib> <tlib−version>0.03</tlib−version> <jsp−version>1.2</jsp−version> <short−name>arcmind</short−name> <uri>http://arcmind.com/jsf/component/tags</uri> <description>ArcMind tags</description> <tag> <name>slabel</name> <tag−class>arcmind.simple.LabelTag</tag−class> <attribute> <name>label</name> <description>The value of the label</description> </attribute> </tag> ...

Advanced Web Technologies 7) Create a new JSF Components Write a simple component: Create a custom tag 20

slide-21
SLIDE 21

start using the tag in JSPs

[test.jsp] <%@ taglib prefix=”arcmind” uri=”http://arcmind.com/jsf/component/tags” %> ... <arcmind:slabel label=”Form Test”/>

Advanced Web Technologies 7) Create a new JSF Components Write a simple component: Create a custom tag 21

slide-22
SLIDE 22

A composite component

◮ The Field component combines the work of several

components into one.

◮ The Field component combines label, text input, and

message functionality into one component.

  • Field’s text input functionality allows users to input text.
  • Its label functionality shows up red if there is a problem (such

as incorrect input) and also presents an asterisk (*) to denote required fields.

  • Its message functionality lets it write out error messages when

required.

◮ The Field component example demonstrates the

following:

  • The UIInput component
  • Working with value bindings and component attributes
  • Decoding values from request parameters
  • Working with error messages

◮ the Field component uses a separate renderer.

Advanced Web Technologies 7) Create a new JSF Components A composite Component 22

slide-23
SLIDE 23

The Field tag

<f:view> <h2>CD Form</h2> <h:form id=”cdForm”> <h:inputHidden id=”rowIndex” value=”#{CDManagerBean.rowIndex}” /> <arcmind:field id=”title” value=”#{CDManagerBean.title}” label=”Title:” errorStyleClass=”errorText” required=”true” /> <br /> <arcmind:field id=”artist” value=”#{CDManagerBean.artist}” label=”Artist:” errorStyleClass=”errorText” required=”true” /> <br /> <arcmind:field id=”price” value=”#{CDManagerBean.price}” label=”CD Price:” errorStyleClass=”errorText” required=”true”> <f:validateDoubleRange maximum=”1000.0” minimum=”1.0”/> </arcmind:field>

Advanced Web Technologies 7) Create a new JSF Components A composite Component: Example of JSP file 23

slide-24
SLIDE 24

HTML outputed by the previous code

<label style=”” class=”errorText”>Artist∗</label> <input type=”text” id=”cdForm:artist ” name=” cdForm:artist ” /> Artist is blank, it must contain characters

Advanced Web Technologies 7) Create a new JSF Components A composite Component: Example of JSP file 24

slide-25
SLIDE 25

FieldComponent subclasses UIInput

package com.arcmind.jsfquickstart; import javax.faces.component.UIInput; import javax.faces.context.FacesContext; /∗∗ @author Richard Hightower ∗/ public class FieldComponent extends UIInput { private String label; @Override public Object saveState(FacesContext context) { Object values[] = new Object[2]; values[0] = super.saveState(context); values[1] = label; return ((Object) (values)); }

Advanced Web Technologies 7) Create a new JSF Components A composite Component: Subclass UIInput 25

slide-26
SLIDE 26

FieldComponent Class (Cont.)

@Override public void restoreState(FacesContext context, Object state) { Object values[] = (Object[])state; super.restoreState(context, values[0]); label = (String)values[1]; } public FieldComponent (){ this.setRendererType(”arcmind.Field”);} public String getLabel() { return label; } public void setLabel(String label) { this.label = label; } @Override public String getFamily() { return ”arcmind.Field”; } public boolean isError() { return !this.isValid(); } }

Advanced Web Technologies 7) Create a new JSF Components A composite Component: Subclass UIInput 26

slide-27
SLIDE 27

Value bindings and component attributes

◮ Field component has several attributes: label,

errorStyle, errorStyleClass, and value.

  • The label and value properties are at the core of the Field

component,

  • but errorStyle and errorStyleClass are HTML specific.
  • Because these attributes are HTML specific, you do not need

to have them as properties in the Field component;

  • instead you will pass them around as component attributes

that only the renderer knows about.

Advanced Web Technologies 7) Create a new JSF Components A composite Component: Subclass UIInput 27

slide-28
SLIDE 28

Creating a custom tag for FieldComponent

package com.arcmind.jsfquickstart; import javax.faces.application.Application; import javax.faces.component.UIComponent; import javax.faces.context.FacesContext; import javax.faces.el.ValueBinding; import javax.faces.webapp.UIComponentTag; /∗∗ @author Richard Hightower ∗/ public class FieldTag extends UIComponentTag { private String label; private String errorStyleClass=””; private String errorStyle=””; private boolean required; private String value=””; public String getLabel() { return label; } public void setLabel(String label) { this.label = label; }

Advanced Web Technologies 7) Create a new JSF Components A composite Component: Creating a custom tag for FieldComponent 28

slide-29
SLIDE 29

The FieldTag Class (Cont.)

@Override public String getComponentType() { return ”arcmind.Field”; } @Override public String getRendererType() { return ”arcmind.Field”; } @Override protected void setProperties(UIComponent component) { /∗ You have to call the super class ∗/ super.setProperties(component); ((FieldComponent)component).setLabel(label); component.getAttributes().put(”errorStyleClass”, errorStyleClass); component.getAttributes().put(”errorStyle”,errorStyle); ((FieldComponent)component).setRequired(required); FacesContext context = FacesContext.getCurrentInstance(); Application application = context.getApplication(); ValueBinding binding = application.createValueBinding(value); component.setValueBinding(”value”, binding); }

Advanced Web Technologies 7) Create a new JSF Components A composite Component: Creating a custom tag for FieldComponent 29

slide-30
SLIDE 30

Getter and Setter methods

public String getErrorStyleClass() { return errorStyleClass; } public void setErrorStyleClass(String errorStyleClass) { this.errorStyleClass = errorStyleClass; } public String getErrorStyle() { return errorStyle; } public void setErrorStyle(String errorStyle) { this.errorStyle = errorStyle; } public boolean isRequired() { return required; } public void setRequired(boolean required) { this.required = required; } public String getValue() { return value; } public void setValue(String value) { this.value = value; } }

Advanced Web Technologies 7) Create a new JSF Components A composite Component: Creating a custom tag for FieldComponent 30

slide-31
SLIDE 31

Comments on setProperties

◮ label property is passed through just as it was in the

previous example,

◮ the errorStyleClass and errorStyle properties are not

passed through.

  • they are added to the attributes map of the JSF component.
  • The Renderer class will then use the attributes map to render

class and style attributes.

  • This setup allows the HTML-specific code to be absent from

your component.

Advanced Web Technologies 7) Create a new JSF Components A composite Component: Creating a custom tag for FieldComponent 31

slide-32
SLIDE 32

Another version for setProperties

protected void setProperties(UIComponent component) { ... FacesContext context = FacesContext.getCurrentInstance(); Application application = context.getApplication(); ValueBinding binding = application.createValueBinding(value); component.setValueBinding(”value”, binding);

◮ This code allows the value property of the Field

component to be bound to a backing bean.

  • For this example: CDManagerBean’s title property to a

Field component as follows: value="#{CDManagerBean.title}".

Advanced Web Technologies 7) Create a new JSF Components A composite Component: Creating a custom tag for FieldComponent 32

slide-33
SLIDE 33

The separate renderer

package com.arcmind.jsfquickstart; import java.io.IOException; import java.util.Iterator; import java.util.Map; import javax.faces.application.FacesMessage; import javax.faces.component.UIComponent; import javax.faces.component.UIInput; import javax.faces.context.FacesContext; import javax.faces.context.ResponseWriter; import javax.faces.convert.Converter; import javax.faces.convert.ConverterException; import javax.faces.el.ValueBinding; import javax.faces.render.Renderer; /∗∗ ∗ @author Richard Hightower ∗ ∗/ public class FieldRenderer extends Renderer { @Override public Object getConvertedValue(FacesContext facesContext, UIComponent component, Object submittedValue) throws ConverterException { //Try to find out by value binding ValueBinding valueBinding = component.getValueBinding(”value”); if (valueBinding == null) return null; Advanced Web Technologies 7) Create a new JSF Components A composite Component: The Renderer 33

slide-34
SLIDE 34

Renderer (Cont.)

Class valueType = valueBinding.getType(facesContext); if (valueType == null) return null; if (String.class.equals(valueType)) return submittedValue; if (Object.class.equals(valueType)) return submittedValue; Converter converter = ((UIInput) component).getConverter(); converter = facesContext.getApplication().createConverter(valueType); if (converter != null ) { return converter.getAsObject(facesContext, component, (String) submittedValue); }else { return submittedValue; } } @Override public void decode(FacesContext context, UIComponent component) { /∗ Grab the request map from the external context ∗/ Map requestMap = context.getExternalContext().getRequestParameterMap(); /∗ Get client ID, use client ID to grab value from parameters ∗/ String clientId = component.getClientId(context); String value = (String) requestMap.get(clientId); FieldComponent fieldComponent = (FieldComponent)component; /∗ Set the submitted value ∗/ ((UIInput)component).setSubmittedValue(value); } Advanced Web Technologies 7) Create a new JSF Components A composite Component: The Renderer 34

slide-35
SLIDE 35

Renderer (Cont.)

@Override public void encodeBegin(FacesContext context, UIComponent component) throws IOException { FieldComponent fieldComponent = (FieldComponent) component; ResponseWriter writer = context.getResponseWriter(); encodeLabel(writer,fieldComponent); encodeInput(writer,fieldComponent); encodeMessage(context, writer, fieldComponent); writer.flush(); } private void encodeMessage(FacesContext context, ResponseWriter writer, FieldComponent fieldComponent) throws IOException { Iterator iter = context.getMessages(fieldComponent.getClientId(context)); while (iter.hasNext()){ FacesMessage message = (FacesMessage) iter.next(); writer.write(message.getDetail()); } } private void encodeLabel(ResponseWriter writer, FieldComponent fieldComponent) throws IOException{ writer.startElement(”label”, fieldComponent); if (fieldComponent.isError()) { String errorStyleClass = (String) fieldComponent.getAttributes().get(”errorStyleClass”); String errorStyle = (String) fieldComponent.getAttributes().get(”errorStyle”); writer.writeAttribute(”style”, errorStyle, ”style”); writer.writeAttribute(”class”, errorStyleClass, ”class”); } writer.write(”” + fieldComponent.getLabel()); if (fieldComponent.isRequired()) { writer.write(”∗”); } writer.endElement(”label”); } Advanced Web Technologies 7) Create a new JSF Components A composite Component: The Renderer 35

slide-36
SLIDE 36

Renderer (Cont.)

private void encodeInput(ResponseWriter writer, FieldComponent fieldComponent) throws IOException{ FacesContext currentInstance = FacesContext.getCurrentInstance(); writer.startElement(”input”, fieldComponent); writer.writeAttribute(”type”, ”text”, ”type”); writer.writeAttribute(”id”, fieldComponent.getClientId(currentInstance), ”id”); writer.writeAttribute(”name”, fieldComponent.getClientId(currentInstance), ”name”); if(fieldComponent.getValue()!=null) writer.writeAttribute(”value”, fieldComponent.getValue().toString(), ”value”); writer.endElement(”input”); } } Advanced Web Technologies 7) Create a new JSF Components A composite Component: The Renderer 36

slide-37
SLIDE 37

Encoding and decoding

◮ The FieldRenderer’s decode method is as follows:

@Override public void decode(FacesContext context, UIComponent component) { Map requestMap = context.getExternalContext().getRequestParameterMap(); String clientId = component.getClientId(context); String value = (String) requestMap.get(clientId); FieldComponent fieldComponent = (FieldComponent)component; ((UIInput)component).setSubmittedValue(value); }

◮ The Field Renderer’s decode method grabs the clientId from the

component to identify the request parameter to be looked up.

◮ The clientId is calculated as the fully qualified name of the component

given its container path. (ex: cdForm:artist, cdForm:price, cdForm:title).

Advanced Web Technologies 7) Create a new JSF Components A composite Component: The Renderer 37

slide-38
SLIDE 38

Encoding

◮ The encoding methods offer no real surprises.

@Override public void encodeBegin(FacesContext context, UIComponent component) throws IOException { FieldComponent fieldComponent = (FieldComponent) component; ResponseWriter writer = context.getResponseWriter(); encodeLabel(writer,fieldComponent); encodeInput(writer,fieldComponent); encodeMessage(context, writer, fieldComponent); writer.flush(); }

Advanced Web Technologies 7) Create a new JSF Components A composite Component: The Renderer 38

slide-39
SLIDE 39

Encoding (Cont.)

◮ The encodeLabel method is responsible for changing the color of the

label in the case of errors and using asterisks (*) to denote required fields, private void encodeLabel(ResponseWriter writer, FieldComponent fieldComponent) throws IOException{ writer.startElement(”label”, fieldComponent); if (fieldComponent.isError()) { String errorStyleClass = (String) fieldComponent.getAttributes() .get(”errorStyleClass”); String errorStyle = (String) fieldComponent.getAttributes() .get(”errorStyle”); writer.writeAttribute(”style”, errorStyle, ”style”); writer.writeAttribute(”class”, errorStyleClass, ”class”); } writer.write(”” + fieldComponent.getLabel()); if (fieldComponent.isRequired()) { writer.write(”∗”); } writer.endElement(”label”); }

Advanced Web Technologies 7) Create a new JSF Components A composite Component: The Renderer 39

slide-40
SLIDE 40

Behold, the mystery method!

◮ use the method getConvertedValues to look up the associated

converter and invoke it. @Override public Object getConvertedValue(FacesContext facesContext, UIComponent component, Object submittedValue) throws ConverterException { ValueBinding valueBinding = component.getValueBinding(”value”); if (valueBinding == null) return null; Class valueType = valueBinding.getType(facesContext); if (valueType == null) return null; if (String.class.equals(valueType)) return submittedValue; if (Object.class.equals(valueType)) return submittedValue; Converter converter = ((UIInput) component).getConverter(); converter = facesContext.getApplication().createConverter(valueType); if (converter != null ) { return converter.getAsObject(facesContext, component, (String) submittedValue); }else { return submittedValue; } }

Advanced Web Technologies 7) Create a new JSF Components A composite Component: The Renderer 40

slide-41
SLIDE 41

Mapping a renderer to a component

Advanced Web Technologies 7) Create a new JSF Components A composite Component: Mapping a renderer to a component 41

slide-42
SLIDE 42

Conclusion

Of course, there are plenty of other topics to be covered in this area

  • emitting component events,
  • internationalizing components,
  • creating UICommand-style components,
  • . . .

◮ Download examples of these sildes:

http://www-128.ibm.com/developerworks/java/ library/j-jsf4/

Advanced Web Technologies 7) Create a new JSF Components Conclusion 42

slide-43
SLIDE 43

References

◮ http://www-128.ibm.com/developerworks/java/

library/j-jsf4/

Advanced Web Technologies 7) Create a new JSF Components Conclusion 43