Extending JSF to Build a Product- Specific UI Framework€¦ · Bryan Basham: Extending JSF to...

Post on 29-Sep-2020

4 views 0 download

Transcript of Extending JSF to Build a Product- Specific UI Framework€¦ · Bryan Basham: Extending JSF to...

Slide 1

© Copyright 2007, StillSecure, Inc.

Bryan Basham: Extending JSF to Build a Product-Specific UI Framework

Colorado Software Summit: October 21 – 26, 2007

Extending JSF to Build a Product-

Specific UI Framework

Bryan Basham

StillSecure, Inc.

b_basham@yahoo.com

© Copyright 2007, StillSecure, Inc.

Bryan Basham: Extending JSF to Build a Product-Specific UI Framework Slide 2

Colorado Software Summit: October 21 – 26, 2007

JavaServer Faces

by Gary Murphy

Choosing a JVM Web Framework

by Matt Raible

UI Design and Developement

by Bryan Basham

Introduction to Grails

by Scott Davis

Other Presentations

© Copyright 2007, StillSecure, Inc.

Bryan Basham: Extending JSF to Build a Product-Specific UI Framework Slide 3

Colorado Software Summit: October 21 – 26, 2007

Topics Mind Map

Reviewof JSF

CustomComponents

DataConversion

DataValidation

ScreenManagement

ExtendingJSF

© Copyright 2007, StillSecure, Inc.

Bryan Basham: Extending JSF to Build a Product-Specific UI Framework Slide 4

Colorado Software Summit: October 21 – 26, 2007

Raising the level of abstraction

Servlet / JavaServer Pages

JavaServer Faces

Cobia UI Framework

Cobia Module

request/response

tags

EL

components

conversion

validation

actions

domain-specific comps

screen management

browser control

© Copyright 2007, StillSecure, Inc.

Bryan Basham: Extending JSF to Build a Product-Specific UI Framework Slide 5

Colorado Software Summit: October 21 – 26, 2007

JSF Fundamentals

Web container

JSF

.................................BackingBean

<jsp>.......</jsp>

ViewRoot

Form

InputText CmdLink...

request a view

creates

comp. tree

extractsdata

rendersview

POSTform data

bindsdata

performaction(s)

<jsp>.......</jsp>

select next view

createscomp. tree

rendersview

© Copyright 2007, StillSecure, Inc.

Bryan Basham: Extending JSF to Build a Product-Specific UI Framework Slide 6

Colorado Software Summit: October 21 – 26, 2007

JSF Life Cycle

existing component tree

ViewRoot

Form

InputText CmdLink...

<jsp>.......</jsp>

new componenttree

FacesServlet

Lif

ecy

cle

RESTOREVIEW

APPLY REQVALUES

PROCESSVALIDATIONS

UPDATEMODEL

PROCESSAPPLICATION

RENDERRESPONSE

restoreState

processDecodes

processValid

ations

proces

sUpdat

es

proces

sAppli

cation

UICompTag

dispatchdoStart

doEnd

execute

render

saveState

encodeBegin

encodeEnd

encodeChildren

© Copyright 2007, StillSecure, Inc.

Bryan Basham: Extending JSF to Build a Product-Specific UI Framework Slide 7

Colorado Software Summit: October 21 – 26, 2007

Topics Mind Map

Reviewof JSF

CustomComponents

DataConversion

DataValidation

ScreenManagement

ExtendingJSF

© Copyright 2007, StillSecure, Inc.

Bryan Basham: Extending JSF to Build a Product-Specific UI Framework Slide 8

Colorado Software Summit: October 21 – 26, 2007

Example: IP address

Domain Model: EthernetInterface class

EthernetInterface

-String:roleName-String:ipAddress-String:netmask-String:macAddress

UI Screen: Edit Ethernet Interface

© Copyright 2007, StillSecure, Inc.

Bryan Basham: Extending JSF to Build a Product-Specific UI Framework Slide 9

Colorado Software Summit: October 21 – 26, 2007

Example: IP address

Domain Model (better OO)

EthernetInterface

-String:roleName-Ipv4Address:ipAddress-NetMask:netmask-String:macAddress

Ipv4Address

-long:address

+mask(int bits):IP +inverseMask(bits):IP+compareTo(IP):int

Comparable<Ipv4Address>

© Copyright 2007, StillSecure, Inc.

Bryan Basham: Extending JSF to Build a Product-Specific UI Framework Slide 10

Colorado Software Summit: October 21 – 26, 2007

Converter in Use

<c:textField id="interfaceRole" value="#{editIntf.interface.role}" validator="#{editIntf.validateRole}" /><c:textField id="ipAddress" value="#{editIntf.interface.ipAddress}" required="true" converterId="converter.Ipv4Address" validator="#{editIntf.validateIpAddress}" /><c:textField id="netmask" value="#{editIntf.interface.netmask}" required="true" converterId="converter.NetMask" validator="#{editIntf.validateNetmask}" /><c:formOutput id="macAddress" value="#{editIntf.interface.macaddr}" />

JSF Container

Ipv4AddressConverter

10.20.30.42

10.20.30.47

ipAddress=“10.20.30.42”

ipAddress=“10.20.30.47”

getAsString()

getAsObject()

© Copyright 2007, StillSecure, Inc.

Bryan Basham: Extending JSF to Build a Product-Specific UI Framework Slide 11

Colorado Software Summit: October 21 – 26, 2007

Converter Configuration

<?xml version="1.0"?><!DOCTYPE faces-config PUBLIC "-//Sun Microsystems, Inc.//DTD JavaServer Faces Config 1.1//EN" "http://java.sun.com/dtd/web-facesconfig_1_1.dtd"><faces-config>

<converter> <description> Converts an Ipv4Address object to and from a String. </description> <converter-id>converter.Ipv4Address</converter-id> <converter-class> org.stillsecure.cobia.web.converters.Ipv4AddressConverter </converter-class> </converter>

<!-- more JSF configuration -->

</faces-config>

© Copyright 2007, StillSecure, Inc.

Bryan Basham: Extending JSF to Build a Product-Specific UI Framework Slide 12

Colorado Software Summit: October 21 – 26, 2007

Converter API

Ipv4AddressConverter

+getAsObject(...String):Object +getAsString(...Object):String

Converter

{from javax.faces.converter}

© Copyright 2007, StillSecure, Inc.

Bryan Basham: Extending JSF to Build a Product-Specific UI Framework Slide 13

Colorado Software Summit: October 21 – 26, 2007

Converter.getAsObject

public Object getAsObject(FacesContext ctx, UIComponent comp, String displayString)throws ConverterException

{ Ipv4Address result = null; try { if ( displayString != null && displayString.trim().length() > 0 ) { result = new Ipv4Address(displayString); } } catch (IllegalArgumentException e) { FacesMessage message = MessageUtils.createFacesMessage(STRING_TO_OBJECT_FAILED, displayString); throw new ConverterException(message); } return result; }

© Copyright 2007, StillSecure, Inc.

Bryan Basham: Extending JSF to Build a Product-Specific UI Framework Slide 14

Colorado Software Summit: October 21 – 26, 2007

Converter.getAsString

public String getAsString(FacesContext ctx, UIComponent comp, Object object)throws ConverterException

{ String result = null; if ( object == null ) return ""; try { Ipv4Address i = (Ipv4Address) object; result = i.toString(); } catch (ClassCastException e) { assert false : e; } return result; }

© Copyright 2007, StillSecure, Inc.

Bryan Basham: Extending JSF to Build a Product-Specific UI Framework Slide 15

Colorado Software Summit: October 21 – 26, 2007

Topics Mind Map

Reviewof JSF

CustomComponents

DataConversion

DataValidation

ScreenManagement

ExtendingJSF

© Copyright 2007, StillSecure, Inc.

Bryan Basham: Extending JSF to Build a Product-Specific UI Framework Slide 16

Colorado Software Summit: October 21 – 26, 2007

JSF provides field-level validation

Validation occurs after conversion

Form-level or multiple field validation

Use a hidden field at end of form

The validator method must extract data

from either components or request params

JSF Validation

© Copyright 2007, StillSecure, Inc.

Bryan Basham: Extending JSF to Build a Product-Specific UI Framework Slide 17

Colorado Software Summit: October 21 – 26, 2007

Validation failures return to the form

and generates a user message:

Example: Roles are unique

© Copyright 2007, StillSecure, Inc.

Bryan Basham: Extending JSF to Build a Product-Specific UI Framework Slide 18

Colorado Software Summit: October 21 – 26, 2007

Validation in Use

JSF Container

BackingBean

role=“Cobia [Internal]”

role=“”JSF

validateRole

ValidatorException

<c:textField id="interfaceRole" value="#{editIntf.interface.role}" validator="#{editIntf.validateRole}" /><c:textField id="ipAddress" value="#{editIntf.interface.ipAddress}" required="true" converterId="converter.Ipv4Address" validator="#{editIntf.validateIpAddress}" /><c:textField id="netmask" value="#{editIntf.interface.netmask}" required="true" converterId="converter.NetMask" validator="#{editIntf.validateNetmask}" /><c:formOutput id="macAddress" value="#{editIntf.interface.macaddr}" />

© Copyright 2007, StillSecure, Inc.

Bryan Basham: Extending JSF to Build a Product-Specific UI Framework Slide 19

Colorado Software Summit: October 21 – 26, 2007

BackingBean.validateRole

public void validateRole(FacesContext ctx, UIComponent comp, Object value)throws ValidatorException

{ String input = value.toString(); String fieldId = component.getId();

// An empty role name is always legal if( input == null || input.length() == 0 ) return;

// The role name "disabled" is always legal if( input.compareToIgnoreCase( DISABLED_ETH_INTERFACE_ROLE ) == 0 ) return;

// more code on next slide

© Copyright 2007, StillSecure, Inc.

Bryan Basham: Extending JSF to Build a Product-Specific UI Framework Slide 20

Colorado Software Summit: October 21 – 26, 2007

BackingBean.validateRole// continued from last slide // Otherwise, verify that the role name is unique amongst this appliance's // other interface role names. boolean isUnique = true; for ( EthernetInterface interface : parentPage.getInterfaces() ) { if ( interface == currentInterface ) continue; if ( input.equals(interface.getRole()) ) { isUnique = false; break; } }

if( !isUnique ) { FacesMessage message = MessageUtils.createFacesMessage(ROLE_NOT_UNIQUE, input); throw new ValidatorException(fieldId, message, input ); } }

© Copyright 2007, StillSecure, Inc.

Bryan Basham: Extending JSF to Build a Product-Specific UI Framework Slide 21

Colorado Software Summit: October 21 – 26, 2007

Topics Mind Map

Reviewof JSF

CustomComponents

DataConversion

DataValidation

ScreenManagement

ExtendingJSF

© Copyright 2007, StillSecure, Inc.

Bryan Basham: Extending JSF to Build a Product-Specific UI Framework Slide 22

Colorado Software Summit: October 21 – 26, 2007

Custom look-and-feel

Support multiple clients (HTML, cell

phones, etc.)

Create complex components

Hide complex HTML

... raise the level of abstraction ...

Why build components?

© Copyright 2007, StillSecure, Inc.

Bryan Basham: Extending JSF to Build a Product-Specific UI Framework Slide 23

Colorado Software Summit: October 21 – 26, 2007

Containers (screens, frames, divisions)

Output

Input

Complex (data tables)

Types of components

© Copyright 2007, StillSecure, Inc.

Bryan Basham: Extending JSF to Build a Product-Specific UI Framework Slide 24

Colorado Software Summit: October 21 – 26, 2007

Tag class (e.g. TextFieldTag)

Component class (e.g. UITextField)

Renderer class (e.g. TextFieldRenderer)

Styles sheet (e.g. TextField.css)

JavaScript code (e.g. TextField.js)

Internatialization (e.g. text.properties)

Elements of components

© Copyright 2007, StillSecure, Inc.

Bryan Basham: Extending JSF to Build a Product-Specific UI Framework Slide 25

Colorado Software Summit: October 21 – 26, 2007

Frame: a container comp.

<c:frame> <!-- PUT YOUR PAGE CONTENT HERE --></c:frame>

© Copyright 2007, StillSecure, Inc.

Bryan Basham: Extending JSF to Build a Product-Specific UI Framework Slide 26

Colorado Software Summit: October 21 – 26, 2007

Frame: elements

Framecomponent

UIFrame.class

FrameTag.class

FrameRenderer.class

div# {.......}

Frame.css

func(){ ...}

Frame.js

<f-c> ...</f-c>

faces-config.xml

<tag> ...</tag>

jsf-comps.tldabc=..xyz=..

text.properties

© Copyright 2007, StillSecure, Inc.

Bryan Basham: Extending JSF to Build a Product-Specific UI Framework Slide 27

Colorado Software Summit: October 21 – 26, 2007

Frame: Tag class

package org.stillsecure.cobia.web.comps.tags;

import org.stillsecure.cobia.web.comps.UIFrame;import javax.faces.webapp.UIComponentTag;

public class FrameTag extends UIComponentTag{ public String getComponentType() { // Associates tag with component in faces-config.xml return UIFrame.COMPONENT_TYPE; }

public String getRendererType() { return UIFrame.RENDERER_TYPE; }

}

© Copyright 2007, StillSecure, Inc.

Bryan Basham: Extending JSF to Build a Product-Specific UI Framework Slide 28

Colorado Software Summit: October 21 – 26, 2007

Frame: Comp. class

package org.stillsecure.cobia.web.comps;import org.stillsecure.cobia.web.comps.util.StyledComponent;import java.util.*;import javax.faces.component.UIComponentBase;

public class UIFrame extends UIComponentBase implements StyledComponent{ public static final String COMPONENT_TYPE = "component.Frame"; public static final String RENDERER_TYPE = "html.Frame"; @Override public String getRendererType() { return RENDERER_TYPE; } @Override public String getFamily() { return COMPONENT_TYPE; }// more code on next slide

© Copyright 2007, StillSecure, Inc.

Bryan Basham: Extending JSF to Build a Product-Specific UI Framework Slide 29

Colorado Software Summit: October 21 – 26, 2007

Frame: Comp. class

package org.stillsecure.cobia.web.comps;

import org.stillsecure.cobia.web.comps.util.StyledComponent;

public class UIFrame extends UIComponentBase implements StyledComponent{// more code on next slide

public Set<StyleInfo> getStyleInfo() { return STYLES; } private static final Set<StyleInfo> STYLES = new HashSet<StyleInfo>(); static { STYLES.add(new StyleInfo(StyleType.CSS, UIFrame.class.getSimpleName())); }}

© Copyright 2007, StillSecure, Inc.

Bryan Basham: Extending JSF to Build a Product-Specific UI Framework Slide 30

Colorado Software Summit: October 21 – 26, 2007

Frame: Renderer class

package org.stillsecure.cobia.web.comps.renderers;

import java.io.IOException;import javax.faces.component.UIComponent;import javax.faces.context.FacesContext;import javax.faces.context.ResponseWriter;import javax.faces.render.Renderer;

public class FrameRenderer extends Renderer{ @Override public void encodeBegin(FacesContext context, UIComponent component) throws IOException { ResponseWriter out = context.getResponseWriter(); out.write(START_TEXT); } private static final String START_TEXT = "<div id='frameTLC'> \n" + " <div id='frameTRC'> \n";// code continued on next slide

© Copyright 2007, StillSecure, Inc.

Bryan Basham: Extending JSF to Build a Product-Specific UI Framework Slide 31

Colorado Software Summit: October 21 – 26, 2007

Frame: Renderer class

public class FrameRenderer extends Renderer{

// code continued from previous slide @Override public void encodeEnd(FacesContext context, UIComponent component) throws IOException { ResponseWriter out = context.getResponseWriter(); out.write(END_TEXT); } private static final String END_TEXT = " </div> \n" + " <div id='frameBLC'> \n" + " <div id='frameBRC'>&nbsp;</div> \n" + " </div> \n" + "</div> \n"; }

© Copyright 2007, StillSecure, Inc.

Bryan Basham: Extending JSF to Build a Product-Specific UI Framework Slide 32

Colorado Software Summit: October 21 – 26, 2007

Frame: CSS file

/* ------ Frame Styles (Creates Gray Area of the Interface) ------------------ */div#frameTLC { /*Left top corner*/

background: url(../images/frame_TLC.gif) top left no-repeat;margin: 0 10px;width: 98%;min-width: 1024px;

}div#frameTRC { /*Right top corner*/

background: url(../images/frame_TRC.gif) top right no-repeat;padding: 10px 0 0 0;

}div#frameBLC { /*Left bottom corner*/

background: url(../images/frame_BLC.gif) bottom left no-repeat;}div#frameBRC { /*Bottom right corner*/

background: url(../images/frame_BRC.gif) bottom right no-repeat;margin: 0 0 0 10px;padding: 10px 0 0 0;

}

© Copyright 2007, StillSecure, Inc.

Bryan Basham: Extending JSF to Build a Product-Specific UI Framework Slide 33

Colorado Software Summit: October 21 – 26, 2007

Frame: tag declaration

<?xml version="1.0" encoding="UTF-8" ?><taglib xmlns="http://java.sun.com/xml/ns/j2ee"

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee

http://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd"version="2.0">

<tlib-version>2.0</tlib-version> <short-name>cobia</short-name> <uri>http://cobia.stillsecure.org/jsf</uri> <tag> <description>

This tag represent the Frame component.This type of widget creates the gray, rounded-edgedstructure around the main body of the page.

</description> <name>frame</name> <tag-class>

org.stillsecure.cobia.web.comps.tags.FrameTag </tag-class> <body-content>scriptless</body-content> </tag></taglib>

© Copyright 2007, StillSecure, Inc.

Bryan Basham: Extending JSF to Build a Product-Specific UI Framework Slide 34

Colorado Software Summit: October 21 – 26, 2007

Frame: comp. declaration

<?xml version="1.0"?><!DOCTYPE faces-config PUBLIC "-//Sun Microsystems, Inc.//DTD JavaServer Faces Config 1.1//EN" "http://java.sun.com/dtd/web-facesconfig_1_1.dtd"><faces-config>

<component> <component-type>component.Frame</component-type> <component-class>

org.stillsecure.cobia.web.comps.UIFrame </component-class> </component>

<renderer> <component-family>component.Frame</component-family> <renderer-type>html.Frame</renderer-type> <renderer-class>

org.stillsecure.cobia.web.comps.renderers.FrameRenderer </renderer-class> </renderer>

</faces-config>

© Copyright 2007, StillSecure, Inc.

Bryan Basham: Extending JSF to Build a Product-Specific UI Framework Slide 35

Colorado Software Summit: October 21 – 26, 2007

ImageList: an input comp.

Required flag

Rollover helpField message (not shown)

ImageList

© Copyright 2007, StillSecure, Inc.

Bryan Basham: Extending JSF to Build a Product-Specific UI Framework Slide 36

Colorado Software Summit: October 21 – 26, 2007

ImageList: complex HTML

<div id="actionSection"> <label><span class="required">*</span> Action:</label> <span class="helpInfo"> <script language="javascript" type="text/javascript"> rolloverHelp('The <span class="reference">Action<\/span> is...'); </script> </span> <div id="actionContainer"> <script language="javascript" type="text/javascript">

var options = new Array();options[0] = new ImageListOption(/* image info, text, and value */);options[1] = new ImageListOption(/* next option data */);

// more optionsvar il = new ImageList("action", "ALLOW", options);il.writeHtml();

</script> </div></div>

<c:colorList id='ruleAction' required='true' type='org.stillsecure.cobia.module.firewall.domain.Action' value='#{editRule.rule.action}' />

UI Design HTML/JavaScript:

Encapsulated in a JSF component:

© Copyright 2007, StillSecure, Inc.

Bryan Basham: Extending JSF to Build a Product-Specific UI Framework Slide 37

Colorado Software Summit: October 21 – 26, 2007

ImageList: elements

ImageListcomponent

UIImageList.class

ImageListTag.class

ImageListRenderer.class

div# {.......}

ImageList.css

func(){ ...}

ImageList.js

<f-c> ...</f-c>

faces-config.xml

<tag> ...</tag>

jsf-comps.tldabc=..xyz=..

text.properties

© Copyright 2007, StillSecure, Inc.

Bryan Basham: Extending JSF to Build a Product-Specific UI Framework Slide 38

Colorado Software Summit: October 21 – 26, 2007

ImageList: model design

«enumeratedType»

Action{from Firewall module}

+ALLOW+DENY+REJECT

«interface»

UiImage

+getPrimaryImage():ImageData+getHighlightedImage():ImageData+getDisabledImage():ImageData

UIImageList

+setType(String):void+getType():Class<Enum>

© Copyright 2007, StillSecure, Inc.

Bryan Basham: Extending JSF to Build a Product-Specific UI Framework Slide 39

Colorado Software Summit: October 21 – 26, 2007

ImageList: component design

UIImageList

+setType(String):void+getType():Class<Enum>

ImageListTag

+setType(String)+setValue(String)+setRequired(boolean)#setProperties(UIComponent)

HtmlInputHidden{j.f.components.html}

+processDecodes+processValidators+processUpdates

UIFieldLabel

UIFieldMessage

UIRolloverHelp

EditableValueHolder{javax.faces.components}

children

UIComponentBase{javax.faces.components}

+getAttributes():List+saveState+restoreState

© Copyright 2007, StillSecure, Inc.

Bryan Basham: Extending JSF to Build a Product-Specific UI Framework Slide 40

Colorado Software Summit: October 21 – 26, 2007

ImageList includes child components

UIComponentBase delegates lifecycle

behavior to children

UIComponentBase automatically stores

state of children

ImageList stores enumType in attributes

hash table

UIComponentBase automatically stores

state attributes hash table

ImageList: design evaluation

© Copyright 2007, StillSecure, Inc.

Bryan Basham: Extending JSF to Build a Product-Specific UI Framework Slide 41

Colorado Software Summit: October 21 – 26, 2007

ImageList: Tag class

public class ImageListTag extends UIComponentTag{ public void setRequired(boolean required) { this.required = required; } private boolean required;

public void setValue(String value) throws JspException { if ( UIComponentTagUtils.isValueReference(value) ) { ValueBinding valueVB = ComponentUtils.createValueBinding(value); this.value = valueVB; } else { throw new JspException("The 'value' attribute must be a JSF value binding."); } } private ValueBinding value = null;// more code on next slide

© Copyright 2007, StillSecure, Inc.

Bryan Basham: Extending JSF to Build a Product-Specific UI Framework Slide 42

Colorado Software Summit: October 21 – 26, 2007

ImageList: Tag class

// code continued from previous slide public void setType(String enumType) { // Check the 'type' Class<Enum> enumClass = EnumUtils.checkType(enumType); if ( ! UiImage.class.isAssignableFrom(enumClass) ) throw new IllegalArgumentException("type must implement UiImage."); // Store it this.enumType = enumType; } private String enumType;

public void release() { super.release(); this.required = false; this.value = null; this.enumType = null; }// more code on next slide

© Copyright 2007, StillSecure, Inc.

Bryan Basham: Extending JSF to Build a Product-Specific UI Framework Slide 43

Colorado Software Summit: October 21 – 26, 2007

ImageList: Tag class

// code continued from previous slide protected void setProperties(UIComponent comp) { UIImageList component = (UIImageList) comp; // Handle basic attributes super.setProperties(component); component.setId(getId()); component.setRequired(this.required); // Process the 'value' value binding component.getInputField().setValueBinding(ComponentUtils.VALUE_ATTR, this.value); // Handle unique attributes component.setType(this.enumType); // Specify the converter EnumConverter converter = new EnumConverter(); converter.setType(this.enumType); component.setConverter(converter); }} // END of ImageListTag class

© Copyright 2007, StillSecure, Inc.

Bryan Basham: Extending JSF to Build a Product-Specific UI Framework Slide 44

Colorado Software Summit: October 21 – 26, 2007

ImageList: Component class

public abstract class UIImageList extends UIComponentBase implements EditableValueHolder{ public void setType(String type) { // Check the 'type' Class<Enum> enumClass = EnumUtils.checkType(type); if ( ! UiImage.class.isAssignableFrom(enumClass) ) throw new IllegalArgumentException("type implement implements UiImage."); // Store the type name (and not the class object) to facilitate serialization this.getAttributes().put(TYPE_ATTR, type); } private static final String TYPE_ATTR = "typeAttr"; public Class<Enum> getType() { if ( this.enumClass == null ) { String type = (String) this.getAttributes().get(TYPE_ATTR); this.enumClass = EnumUtils.checkType(type); } return this.enumClass; } private transient Class<Enum> enumClass;// more code on the next slide

© Copyright 2007, StillSecure, Inc.

Bryan Basham: Extending JSF to Build a Product-Specific UI Framework Slide 45

Colorado Software Summit: October 21 – 26, 2007

ImageList: Component class

// code continued from previous slide

public HtmlInputHidden getInputField() { if ( this.childInput == null ) { String childID = String.format("%sInput", getId()); this.childInput = ComponentUtils.findComponentByClass(this, childID, HtmlInputHidden.class); if ( this.childInput == null ) { this.childInput = new HtmlInputHidden(); this.childInput.setId(childID); this.getChildren().add(this.childInput); } } return this.childInput; } private transient HtmlInputHidden childInput;

// more code on the next slide

© Copyright 2007, StillSecure, Inc.

Bryan Basham: Extending JSF to Build a Product-Specific UI Framework Slide 46

Colorado Software Summit: October 21 – 26, 2007

ImageList: Component class

// code continued from previous slide

// // EditableValueHolder methods // public void setConverter(Converter converter) { getInputField().setConverter(converter); } public void setValue(Object value) { getInputField().setValue(value); } public Object getValue() { return getInputField().getValue(); } // many other EVH methods; all delegate to the hidden input field

} // END of UIImageList component class

© Copyright 2007, StillSecure, Inc.

Bryan Basham: Extending JSF to Build a Product-Specific UI Framework Slide 47

Colorado Software Summit: October 21 – 26, 2007

ImageList: Renderer class

public class ImageListRenderer extends Renderer{ public void encodeBegin(FacesContext context, UIComponent comp) throws IOException { UIImageList component = (UIImageList) comp; ResponseWriter out = context.getResponseWriter(); // Render the container <div> tag out.startElement(HTML.DIV_ELEM, component); out.writeAttribute(HTML.ID_ATTR, String.format("%sDIV", comp.getId()), null); // Encode field message encodeFieldMessage(context, component); // Encode the label encodeLabel(context, component); // Encode the help text encodeHelpText(context, component);

// Encode the hidden component tags <input type='hidden'... /> // This field holds the actual data for this component. encodeInputField(context, component);

// Encode the JavaScript for the list HTML component encodeList(context, component); // Encode JavaScript functions used by this component encodeSetFunction(context, component); }// more code on the next slide

© Copyright 2007, StillSecure, Inc.

Bryan Basham: Extending JSF to Build a Product-Specific UI Framework Slide 48

Colorado Software Summit: October 21 – 26, 2007

ImageList: Renderer class

// code continued from previous slide

public boolean getRendersChildren() { return true; } public void encodeChildren(FacesContext context, UIComponent component) throws IOException { // do nothing; all children are hidden } public void encodeEnd(FacesContext context, UIComponent comp) throws IOException { ResponseWriter out = context.getResponseWriter(); // Encode the end <div> tag out.endElement(HTML.DIV_ELEM); }

// more code on the next slide

© Copyright 2007, StillSecure, Inc.

Bryan Basham: Extending JSF to Build a Product-Specific UI Framework Slide 49

Colorado Software Summit: October 21 – 26, 2007

ImageList: Renderer class

// code continued from previous slide

private void encodeInputField(FacesContext context, UIImageList component) throws IOException { ResponseWriter out = context.getResponseWriter(); out.write(" "); component.getInputField().encodeBegin(context); component.getInputField().encodeEnd(context); out.write('\n'); }

private void encodeLabel(FacesContext context, AbstractSpecialtyList component) throws IOException { ResponseWriter out = context.getResponseWriter(); out.write(" "); component.getLabel().encodeBegin(context); component.getLabel().encodeEnd(context); out.write('\n'); }

// more code on the next slide

© Copyright 2007, StillSecure, Inc.

Bryan Basham: Extending JSF to Build a Product-Specific UI Framework Slide 50

Colorado Software Summit: October 21 – 26, 2007

ImageList: Renderer class

// code continued from previous slide private void encodeList(FacesContext context, UImageList component) throws IOException { String compID = component.getId(); ResponseWriter out = context.getResponseWriter();

out.write(String.format(COMP_START_TEMPLATE, compID)); // Create JS variables out.write(String.format(COMP_CREATE_VARS_TEMPLATE, compID, component.getValue())); // Create each image option int index = 0; for ( Enum optionVal : component.getType().getEnumConstants() ) { UiImage option = (UiImage) optionVal; ImageData primaryImage = option.getPrimaryImage(); ImageData highlightedImage = option.getHighlightedImage(); // Create the ImageListOption out.write(String.format(COMP_CREATE_AN_OPTION_TEMPLATE, compID, index, /* other data to template */)); // Increment the index index++; }// more code on the next slide

© Copyright 2007, StillSecure, Inc.

Bryan Basham: Extending JSF to Build a Product-Specific UI Framework Slide 51

Colorado Software Summit: October 21 – 26, 2007

ImageList: Renderer class

// code continued from previous slide // Create COMP variable out.write(String.format(COMP_CREATE_COMP_VAR_TEMPLATE, compID)); // Encode the end of the component's JavaScript out.write(String.format(COMP_END_TEMPLATE, compID));

} // END of encodeList method

private static final String COMP_START_TEMPLATE // 1$=compID = " <div id='%1$sContainer'> %n" +" <script language='javascript' type='text/javascript'> %n"; private static final String COMP_CREATE_VARS_TEMPLATE // 1$=compID 2$=current value = " var %1$sSelectedValue = '%2$s'; %n" +" var %1$sImageOptions = new Array(); %n";

private static final String COMP_CREATE_AN_OPTION_TEMPLATE = " %1$sImageOptions[%2$d] %n" +" = new ImageListOption( %n" +" new ImageListIcon('%3$s', %4$d, %5$d), %n" +" new ImageListIcon('%6$s', %7$d, %8$d), %n" +" '%9$s', '%10$s'); %n"; private static final String COMP_CREATE_COMP_VAR_TEMPLATE // 1$=compID = " var %1$sComponent = new ImageList('%1$s', %1$sSelectedValue, %1$sImageOptions); %n";

private static final String COMP_END_TEMPLATE // 1$=compID = " %1$sComponent.writeHtml(); %n" +" </script> %n" +" </div> %n";

// more code on the next slide

© Copyright 2007, StillSecure, Inc.

Bryan Basham: Extending JSF to Build a Product-Specific UI Framework Slide 52

Colorado Software Summit: October 21 – 26, 2007

ImageList: Renderer class

// code continued from previous slide

private void encodeSetFunction(FacesContext context, UIImageList component) throws IOException { ResponseWriter out = context.getResponseWriter(); String compID = component.getId(); String inputFieldID = component.getInputField().getClientId(WebContext.getFacesContext()); out.write(String.format(SET_FUNCTION_TEMPLATE, compID, inputFieldID)); } private static final String SET_FUNCTION_TEMPLATE // 1$=compID 2$=clientID = " <script language='javascript' type='text/javascript'> %n" +" function set_%1$s() { %n" +" var value = %1$sComponent.getSelectedValue(); %n" +" $('%2$s').value = value; %n" +" } %n" +" navigation.addSubmitAction(set_%1$s); %n" +" </script> %n";

} // END of ImageListRenderer class

© Copyright 2007, StillSecure, Inc.

Bryan Basham: Extending JSF to Build a Product-Specific UI Framework Slide 53

Colorado Software Summit: October 21 – 26, 2007

ImageList: design recap

UIImageList

+setType(String):void+getType():Class<Enum>

ImageListTag

+setType(String)+setValue(String)+setRequired(boolean)#setProperties(UIComponent)

HtmlInputHidden{j.f.components.html}

+processDecodes+processValidators+processUpdates

UIFieldLabel

UIFieldMessage

UIRolloverHelp

EditableValueHolder{javax.faces.components}

children

UIComponentBase{javax.faces.components}

+getAttributes():List+saveState+restoreState

ImageListRenderer

+encodeBegin+getRendersChildren+encodeChildren+encodeInputField ...+encodeList+makeSetFunction

© Copyright 2007, StillSecure, Inc.

Bryan Basham: Extending JSF to Build a Product-Specific UI Framework Slide 54

Colorado Software Summit: October 21 – 26, 2007

EntitySet: a complex comp.

<c:sectionHeading id='ripRoutes' /><c:entitySet id='ripInterfacesTable' value='#{ripMgr.ripInterfaces}' var='rip'

allowsAdd='true' allowsEdit='true' allowsDelete='true'> <c:column id='interface' value='#{rip.ethInterface.device}' sort='true' /> <c:column id='interfaceStatus' value='#{rip.ethInterface.status}' sort='true' /> <c:column id='interfaceRole' value='#{rip.ethInterface.role}' sort='true' /> <c:column id='ipAddress' value='#{rip.ethInterface.ipAddress}' sort='true' /> <c:column id='interfaceNetmask' value='#{rip.ethInterface.netmask}' sort='false' /> <c:column id='ripEnabled' value='#{rip.enabled}' sort='false' /> <c:column id='metric' value='#{rip.metric}' sort='true' type='Numeric' /> <c:column id='authentication' value='#{rip.authentication.type}' sort='false' /></c:entitySet>

© Copyright 2007, StillSecure, Inc.

Bryan Basham: Extending JSF to Build a Product-Specific UI Framework Slide 55

Colorado Software Summit: October 21 – 26, 2007

Represents a table of entity objects

Includes controls to add, edit, and/or

delete objects from the set

Includes subcomponents to control columns

Includes controls to sort on a specific column

EntitySet: a complex comp.

© Copyright 2007, StillSecure, Inc.

Bryan Basham: Extending JSF to Build a Product-Specific UI Framework Slide 56

Colorado Software Summit: October 21 – 26, 2007

EntitySet: elements

EntitySetcomponent

UIEntitySet.class

EntitySetTag.class

EntitySetRenderer.class

div# {.......}

EntitySet.css

func(){ ...}

EntitySet.js

<f-c> ...</f-c>

faces-config.xml

<tag> ...</tag>

jsf-comps.tldabc=..xyz=..

text.properties

© Copyright 2007, StillSecure, Inc.

Bryan Basham: Extending JSF to Build a Product-Specific UI Framework Slide 57

Colorado Software Summit: October 21 – 26, 2007

EntitySet: model design

UIEntitySet

-VB=#{ripMgr.ripInterfaces}

introspect to extract

column data

«backingBean»

RipInterfaceManager{from Router web package}

+getRipInterfaces():List+setRipInterfaceIndex(int)+addRipInterface():String+editRipInterface():String+deleteRipInterface():String

«Cobia Entity»

RipInterface{from Router domain package}

+getInterface():EthInterface+setInterface(EthInterface)+isEnabled():boolean+setEnabled(boolean)+getMetric():int+setMetric(int)EntitySetRenderer

retrieves the collectionfrom the backing beanusing a value binding

© Copyright 2007, StillSecure, Inc.

Bryan Basham: Extending JSF to Build a Product-Specific UI Framework Slide 58

Colorado Software Summit: October 21 – 26, 2007

EntitySet: component design

UIEntitySet

+setValue(String):void+getColumns():List

EntitySetTag

+setValue(String)+setVar(String)+setAllowsAdd(boolean)+setAllowsEdit(boolean)+setAllowsDelete(boolean)#setProperties(UIComponent)

HtmlInputHidden{j.f.components.html}

-VB:#{ripMgr.ripInterfaceIndex}

children

ColumnTag

+setValue(String)+setType(String)+setSort(boolean)#setProperties(UIComponent)

UIColumn

-VB=#{rip.interface}

HtmlCommandLink{j.f.components.html}

-MB:#{ripMgr.addRipInterface}

HtmlCommandLink{j.f.components.html}

-MB:#{ripMgr.editRipInterface}

...

...

UIColumn

-VB=#{rip.enabled} ColumnTag

...

© Copyright 2007, StillSecure, Inc.

Bryan Basham: Extending JSF to Build a Product-Specific UI Framework Slide 59

Colorado Software Summit: October 21 – 26, 2007

EntitySet: Rendered template

<div class="addItemTable"> <ul class="addItem"> <li> <a href="#" onclick="return oamSubmitForm(...);" id="x:ripInterfacesTable-addLink">

add a rip interface </a> </li> </ul></div><input id="x:ripInterfacesTableIndex" name="x:ripInterfacesTableIndex" value="0" type="hidden"><a href="#" onclick="return oamSubmitForm(...);" id="x:ripInterfacesTable-editLink"></a><script language="javascript" type="text/javascript"> function ripInterfacesTable_editAction(index) { document.getElementById('x:ripInterfacesTableIndex').value = index; return document.getElementById('x:ripInterfacesTable-editLink').onclick(); }</script><a href="#" onclick="return oamSubmitForm(...);" id="x:ripInterfacesTable-deleteLink"></a><script language="javascript" type="text/javascript"> function ripInterfacesTable_deleteAction(index) { document.getElementById('x:ripInterfacesTableIndex').value = index; return document.getElementById('x:ripInterfacesTable-deleteLink').onclick(); }</script><!-- more code on next slide -->

© Copyright 2007, StillSecure, Inc.

Bryan Basham: Extending JSF to Build a Product-Specific UI Framework Slide 60

Colorado Software Summit: October 21 – 26, 2007

EntitySet: Rendered template

<!-- continued code from previous slide --><div class="dataTableContainerScrollable" id="ripInterfacesTable"> <table cellpadding="0" cellspacing="0" border="0"> <thead id="ripInterfacesTableHead"> <tr> <th class="dataTableHeaderString dataTableHeaderFirst" id="interface">interface</th> <th class="dataTableHeaderString" id="interfaceStatus">status</th>

<!-- more column TH cells --> <th class="dataTableHeaderAction" id="edit">&nbsp;</th> <th class="dataTableHeaderAction dataTableHeaderLast" id="delete">&nbsp;</th>

</tr> </thead> <tbody id="ripInterfacesTableBody"> <tr> <th class="dataTableString dataTableCellFirst" headers="interface">eth0</th>

<td class="dataTableString" headers="interfaceStatus">up</td> <!-- more column TD cells --> <td class="dataTableAction" headers="edit"> <a href="#" onclick="return ripInterfacesTable_editAction(0);">edit</a> </td> <td class="dataTableAction dataTableCellLast" headers="delete"> <a href="#" onclick="return ripInterfacesTable_deleteAction(0);">edit</a> </td>

</tr> <!-- more entity rows --> </tbody> </table></div>

© Copyright 2007, StillSecure, Inc.

Bryan Basham: Extending JSF to Build a Product-Specific UI Framework Slide 61

Colorado Software Summit: October 21 – 26, 2007

EntitySet: Backing bean

public class ConfigureRIP extends AbstractUpdateContent{ // UIEntitySet component id='ripInterfacesTable' private Set<RipInterface> ripInterfacesSet; public void setRipInterfacesSet(Set<RipInterface> ripInterfaces) { ripInterfacesSet = ripInterfaces; } private List<RipInterface> ripInterfaces; public List<RipInterface> getRipInterfaces() { if ( ripInterfaces == null ) { ripInterfaces = new ArrayList<RipInterface>(ripInterfacesSet.size()); for ( RipInterface item : ripInterfacesSet ) { ripInterfaces.add(item); }

// PERFORM SORT (NOT SHOWN) } return ripInterfaces; } protected void clearRipInterfaces() { ripInterfaces = null; }// more code on next slide

© Copyright 2007, StillSecure, Inc.

Bryan Basham: Extending JSF to Build a Product-Specific UI Framework Slide 62

Colorado Software Summit: October 21 – 26, 2007

EntitySet: Backing bean

// code continued from previous slide

/** * Implements the "add a rip interface" action method. */ public String addRipInterface() { // Create the new RIP interface and pass to screen RipInterface ripInterface = new RipInterface(); ripInterface.setState(Entity.State.ADDED); AddRipInterface addScreen = new AddRipInterface(this, ripInterface); return addScreen.open(); } /** * Adds a new RIP interface to the set. This is used by the AddRipInterface * screen backing bean. */ public void addRipInterface(RipInterface addedRip) { ripInterfacesSet.add(addedRip); clearRipInterfaces(); }

// more code on next slide

© Copyright 2007, StillSecure, Inc.

Bryan Basham: Extending JSF to Build a Product-Specific UI Framework Slide 63

Colorado Software Summit: October 21 – 26, 2007

EntitySet: Backing bean

// code continued from previous slide

/** Maps to the hidden input with VB=#{ripMgr.ripInterfacesIndex} */ private int ripInterfacesIndex; public int getRipInterfacesIndex() { return ripInterfacesIndex; } public void setRipInterfacesIndex(int index) { ripInterfacesIndex = index; } protected RipInterface getRipInterface() { return ripInterfaces.get(ripInterfacesIndex); } public String editRipInterface() { EditRipInterface editScreen = new EditRipInterface(this, getRipInterface()); return editScreen.open(); } // more code in backing bean

} // END of ConfigureRIP class

© Copyright 2007, StillSecure, Inc.

Bryan Basham: Extending JSF to Build a Product-Specific UI Framework Slide 64

Colorado Software Summit: October 21 – 26, 2007

Topics Mind Map

Reviewof JSF

CustomComponents

DataConversion

DataValidation

ScreenManagement

ExtendingJSF

© Copyright 2007, StillSecure, Inc.

Bryan Basham: Extending JSF to Build a Product-Specific UI Framework Slide 65

Colorado Software Summit: October 21 – 26, 2007

Simplify the HTML/JSP

UIScreen component: styles and scripts

Boundary components: JSP and backing

bean

Manage breadcrumbs

Manage conversation state

Screen Mgt: requirements

© Copyright 2007, StillSecure, Inc.

Bryan Basham: Extending JSF to Build a Product-Specific UI Framework Slide 66

Colorado Software Summit: October 21 – 26, 2007

DEMO: UI Design is rich

GeneralSettings: 196 lines (14)

ConfigureRIP: 299 lines (103)

EditFirewallRule: 583 lines (416)

Simplify HTML

© Copyright 2007, StillSecure, Inc.

Bryan Basham: Extending JSF to Build a Product-Specific UI Framework Slide 67

Colorado Software Summit: October 21 – 26, 2007

Phase one uses:

raw HTML

standard JSP component

Tiles framework from Struts

GeneralSettings: 43 lines (21)

ConfigureRIP: 88 lines (67)

EditFirewallRule: 430 lines (385)

Simplify HTML: phase one

© Copyright 2007, StillSecure, Inc.

Bryan Basham: Extending JSF to Build a Product-Specific UI Framework Slide 68

Colorado Software Summit: October 21 – 26, 2007

Phase two uses Cobia UI components

GeneralSettings: 52 lines (7)

ConfigureRIP: 63 lines (18)

EditFirewallRule: 83 lines (35)

Simplify HTML: phase two

© Copyright 2007, StillSecure, Inc.

Bryan Basham: Extending JSF to Build a Product-Specific UI Framework Slide 69

Colorado Software Summit: October 21 – 26, 2007

UIScreen is the “root” component

Renders the DOCTYPE, <html>, <head>,

and <body> tags

Includes necessary JavaScript files

Includes necessary CSS files

... well, OK, it's not the JSF root

UIScreen

© Copyright 2007, StillSecure, Inc.

Bryan Basham: Extending JSF to Build a Product-Specific UI Framework Slide 70

Colorado Software Summit: October 21 – 26, 2007

UIScreen: JSPX template

<jsp:root xmlns:jsp='http://java.sun.com/JSP/Page' version='2.0'xmlns:f='http://java.sun.com/jsf/core'xmlns:h='http://java.sun.com/jsf/html'xmlns:c='http://cobia.stillsecure.org/jsf'>

<jsp:directive.page contentType='text/html; charset=UTF-8' /><f:view><c:screen value='#{BEAN-NAME}'><h:form id='x'>

<c:division id='header'> <!-- LOGO / APPLICATION NAV --> </c:division> <c:division id='container'> <!-- MAIN PAGE CONTENT --> </c:division> <c:division id='footer'> <!-- COPYRIGHT / VERSION / LICENSE --> </c:division> </h:form></c:screen></f:view></jsp:root>

© Copyright 2007, StillSecure, Inc.

Bryan Basham: Extending JSF to Build a Product-Specific UI Framework Slide 71

Colorado Software Summit: October 21 – 26, 2007

UIScreen: component tree

UIViewRoot

UIScreen

UIForm

UIDivision UIDivision UIDivision

UIModNav UIBcTrail UIFrame

UIScrMsgs UIScrButtons UIFullFrame

UIDrpDwnList UIBoolChkbox... UIImageList...

CSS CSSCSS

CSS

CSS

JSJSJS

JS

CSS CSS CSS

CSSCSS

JS

© Copyright 2007, StillSecure, Inc.

Bryan Basham: Extending JSF to Build a Product-Specific UI Framework Slide 72

Colorado Software Summit: October 21 – 26, 2007

Jacobson's analysis model

Boundary (UI)

Service (aka Control)

Entity (aka Domain object)

Boundary components

Boundary

Service

Entity

EditRipInterface

RipInterface

XorpManager

© Copyright 2007, StillSecure, Inc.

Bryan Basham: Extending JSF to Build a Product-Specific UI Framework Slide 73

Colorado Software Summit: October 21 – 26, 2007

Boundary components

EditRipInterface.class

<jsp> ... ....</jsp>

EditRipInterface.jspx

EditRipInterface

Boundary == View + Controller

© Copyright 2007, StillSecure, Inc.

Bryan Basham: Extending JSF to Build a Product-Specific UI Framework Slide 74

Colorado Software Summit: October 21 – 26, 2007

Screen backing beans

<jsp> ... ....</jsp>

EditRipInterface.jspx

UIScreen

+getScreen():Screen+encodeBegin

«enumeratedType»

ScreenType

+DASHBOARD+MULTI_PAGE+FULL_SCREEN

«interface»

Screen

+getType():ScreenType+getViewId():String+open():String+refresh():String+free():void

«interface»

UpdateScreen

+isModified():boolean+save():void

AbstractScreen

{abstract}

AbsUpdateScreen

{abstract}

EditRipInterface{from Router module}

<c:screen value=#{ripMgr}>

ripMgr is stored in session-scope

© Copyright 2007, StillSecure, Inc.

Bryan Basham: Extending JSF to Build a Product-Specific UI Framework Slide 75

Colorado Software Summit: October 21 – 26, 2007

Screen hierarchies

Dashboard

ConfigureRIP

ConfigureBGP

ConfigureStaticRoutes

AddRipInterface

EditRipInterface

EditBgpPeer

EditStaticRoute

© Copyright 2007, StillSecure, Inc.

Bryan Basham: Extending JSF to Build a Product-Specific UI Framework Slide 76

Colorado Software Summit: October 21 – 26, 2007

Breadcrumb trail

UI view of breadcrumb trail

«screen»

Dashboard«screen»

ConfigureRIP«screen»

EditRipInterfaceparent parent

Screen parent relationship

© Copyright 2007, StillSecure, Inc.

Bryan Basham: Extending JSF to Build a Product-Specific UI Framework Slide 77

Colorado Software Summit: October 21 – 26, 2007

Manage UI conversation

ScreenBean manages saving or canceling screen state

UpdateScreen buttons

«screen»

Dashboard«screen»

ConfigureRIP«screen»

EditRipInterfaceparent parent

«backingBean»

ScreenBean

if isModified,then save

pop toparent

© Copyright 2007, StillSecure, Inc.

Bryan Basham: Extending JSF to Build a Product-Specific UI Framework Slide 78

Colorado Software Summit: October 21 – 26, 2007

Topics Mind Map

Reviewof JSF

CustomComponents

DataConversion

DataValidation

ScreenManagement

ExtendingJSF