Upload
andy-schwartz
View
4.300
Download
1
Embed Size (px)
DESCRIPTION
JSF Summit 2009 presentation covering three component-centric web frameworks: JSF, Wicket and Tapestry.
Citation preview
1Component Framework Primer
Component Framework Primer for JSF Users
Andy Schwartz | Oracle Corporation
2Component Framework Primer
What? What are we doing?
– Comparing server-side component-centric frameworks– Understanding approaches to common problems
What is a server-side component-centric framework?– User interface component model defined on server– Components hold properties, children, fire events– Swing-like approach for web content
What frameworks?– JSF, Wicket and Tapestry
What else is there?– Client-side (jQuery, Dojo)– Hybrid (GWT) – MVC (Struts, RoR)
3Component Framework Primer
Why? JSF has historically been a target of criticism Often compared to related frameworks Important to understand JSF’s limitations JSF 2 addresses many of these issues Still room for improvement We can learn from other frameworks We can continue to evolve/improve JSF
4Component Framework Primer
Why Wicket and Tapestry? Similar in scope to JSF Popular choices Many areas of overlap Different approaches Interesting comparisons Plenty of lessons to learn
5Component Framework Primer
Who? User Interface Technology Architect, Oracle Developing user interface frameworks since 1993 JSR-314/JSF 2.0 Expert Group Representative Wicket/Tapestry Student Biased, but honest :-)
6Component Framework Primer
Agenda Hello, Frameworks! Event Handling Ajax Navigation Input Processing Custom components Wrap up
7Component Framework Primer
Hello, JSF!
8Component Framework Primer
JSF History Originally standardized under JSR-127, 2004. Standard piece of Java EE platform (Web Profile) Sun serves as spec lead (Ed Burns, Roger Kitain) JSR-252/JSF 1.2 enhancements, 2006 JSR-314/JSF 2.0 major release, 2009 Two widely used implementations
– Mojarra (Reference Implementation)– MyFaces
9Component Framework Primer
JSF Vision Swing-like component/event model Declarative component tree specification Integration with existing standards Split logical (components) and physical (markup) Tooling Extensibility
10Component Framework Primer
What is a Page? Legacy: Each page defined by a JSP (JSPX) Now: Facelets standardized, preferred over JSP Combines XHTML and component tags Component tree definition specified via tags Other view declaration languages (VDLs) available
– JSF Templating, Gracelets
11Component Framework Primer
Saying Hello(JSF)
12Component Framework Primer
Grunge: web.xml <servlet>
<servlet-name>Faces Servlet</servlet-name>
<servlet-class>
javax.faces.webapp.FacesServlet
</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>*.jsf</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>Faces Servlet</servlet-name>
<servlet-class>
javax.faces.webapp.FacesServlet
</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>*.jsf</url-pattern>
</servlet-mapping>
13Component Framework Primer
My First JSF Page
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html">
<head><title>My First JSF Page</title></head>
<body>
<!-- Our first JSF component usage -->
Hello, <h:outputText value="World"/>!
</body>
</html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html">
<head><title>My First JSF Page</title></head>
<body>
<!-- Our first JSF component usage -->
Hello, <h:outputText value="World"/>!
</body>
</html>
14Component Framework Primer
JSF Rendering Page definition drives component tree creation Component tree contains UIComponent instances UIComponents delegate to Renderers Response produced by traversing component tree UIComponents/Renderers generate markup Markup written via ResponseWriter
15Component Framework Primer
What Happens After Rendering? Component tree state saved via StateManager State stored in session or client Component tree restored on postback JSF 2.0 optimization: partial state saving
16Component Framework Primer
Bindings Component attributes can be bound Allows components to access dynamic data Specified via Unified Expression Language (EL) Bindings used for both reading and writing
17Component Framework Primer
A Simple Binding
<h:outputText value="#{sessionScope.user.firstName}"/>
<h:outputText value="#{sessionScope.user.firstName}"/>
18Component Framework Primer
Implicit Objects Bindings have access implicit objects/scopes Servlet-related scopes:
– applicationScope– sessionScope– requestScope
JSF-specific scopes– viewScope– flash– component
Many more objects exposed
19Component Framework Primer
Managed Beans POJOs Named Scoped Container-managed
20Component Framework Primer
Managed Bean Registration
<faces-config>
<managed-bean>
<managed-bean-name>user</managed-bean-name>
<managed-bean-class>demo.User</managed-bean-class>
<managed-bean-scope>session</managed-bean-scope>
</managed-bean>
</faces-config>
<faces-config>
<managed-bean>
<managed-bean-name>user</managed-bean-name>
<managed-bean-class>demo.User</managed-bean-class>
<managed-bean-scope>session</managed-bean-scope>
</managed-bean>
</faces-config>
21Component Framework Primer
Managed Bean Registration
@ManagedBean@SessionScopedpublic class User{ public String getFirstName() { … }}
@ManagedBean@SessionScopedpublic class User{ public String getFirstName() { … }}
22Component Framework Primer
Managed Bean Reference
<!-- Instead of this: --><h:outputText value="#{sessionScope.user.firstName}"/>
<!-- We can now do this: --><h:outputText value="#{user.firstName}"/>
<!-- Instead of this: --><h:outputText value="#{sessionScope.user.firstName}"/>
<!-- We can now do this: --><h:outputText value="#{user.firstName}"/>
23Component Framework Primer
Hello, Wicket!
24Component Framework Primer
Wicket Quick History Founded by Johnathan Locke, 2005 Originally hosted at SourceForge Moved to Apache, 2007 Graduated to top level project, June 2007 Current version: 1.4.3 (as of November 2009)
25Component Framework Primer
Wicket Vision Complete separation of markup and logic Web designers do HTML Application developers do Java Designers benefit from previewability Developers benefit from type-safety No special tooling required
26Component Framework Primer
What is a Page? Markup lives in a .html file Code/components live in a .java file Properties/messages in a .properties file All files live on the class path All files for a page share a name Components correlated across html/java by id
27Component Framework Primer
Saying Hello(Wicket)
28Component Framework Primer
Grunge: web.xml
<filter>
<filter-name>wicket</filter-name>
<filter-class>
org.apache.wicket.protocol.http.WicketFilter
</filter-class>
<filter-mapping>
<filter-name>wicket</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</filter>
<filter>
<filter-name>wicket</filter-name>
<filter-class>
org.apache.wicket.protocol.http.WicketFilter
</filter-class>
<filter-mapping>
<filter-name>wicket</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</filter>
29Component Framework Primer
Grunge: web.xml
<init-param> <param-name> applicationClassName </param-name> <param-value> org.demo.wicket.HelloApplication </param-value></init-param>
<init-param> <param-name> applicationClassName </param-name> <param-value> org.demo.wicket.HelloApplication </param-value></init-param>
30Component Framework Primer
My First Wicket Application
public class HelloApplication
extends WebApplication {
@Override
public Class<Hello> getHomePage() {
return Hello.class;
}
}
public class HelloApplication
extends WebApplication {
@Override
public Class<Hello> getHomePage() {
return Hello.class;
}
}
31Component Framework Primer
My First Wicket Page (HTML)
<html xmlns:wicket="…">
<head><title>Hello, Wicket!</title></head>
<body>
<!-- My first Wicket component (html) -->
Hello, <span wicket:id="name">Foo</span>!
</body>
</html>
<html xmlns:wicket="…">
<head><title>Hello, Wicket!</title></head>
<body>
<!-- My first Wicket component (html) -->
Hello, <span wicket:id="name">Foo</span>!
</body>
</html>
32Component Framework Primer
My First Wicket Page (Java)
public class Hello extends WebPage {
public Hello() {
// My first Wicket component (Java)
add(new Label("name", "World"));
}
}
public class Hello extends WebPage {
public Hello() {
// My first Wicket component (Java)
add(new Label("name", "World"));
}
}
33Component Framework Primer
Wicket Rendering Markup exposed via MarkupStream
– MarkupElements: RawText, ComponentTag ComponentTags correlated with Components onRender() called for each component onComponentTag(): modify/render start tag onComponentBodyTag(): modify/render body MarkupElements written to response.
34Component Framework Primer
What Happens After Rendering? Page state stored in page store Pluggable page store behavior
– DiskPageStore leverages file system for old pages
Page restored on postback
35Component Framework Primer
What is a Wicket Model?
Wicket models bind domain layer objects to components.
(Similar to EL ValueExpressions in JSF)
36Component Framework Primer
IModel Contract
T getObject()void setObject(T object)
T getObject()void setObject(T object)
37Component Framework Primer
Components and Models
IModel<?> getDefaultModel()
Most components read from model.Some components write to model.
38Component Framework Primer
Simple Model
Model class implements IModel Stores model object locally We have been using it already
39Component Framework Primer
Simple Model Sample
// This:
add(new Label("name", "World");
// Is shorthand for:
add(new Label("name", new Model("World")));
// This:
add(new Label("name", "World");
// Is shorthand for:
add(new Label("name", new Model("World")));
40Component Framework Primer
Static Model
Simple Models are static.
// This is static:
add(new Label("random",
new Model<Double>(Math.random())
));
// This is static:
add(new Label("random",
new Model<Double>(Math.random())
));
41Component Framework Primer
Dynamic Model
Override getObject() for dynamic.
// This is dynamic:
add(new Label("reallyRandom",
new Model<Double>() {
public Double getObject() {
return Math.random();
}
}));
// This is dynamic:
add(new Label("reallyRandom",
new Model<Double>() {
public Double getObject() {
return Math.random();
}
}));
42Component Framework Primer
Some More Models PropertyModel CompoundPropertyModel LoadableDetachableModel ResourceModel
43Component Framework Primer
Hello, Tapestry!
44Component Framework Primer
Tapestry Quick History Founded by Howard Lewis Ship, 2000 Hosted at Apache Graduated to top level project, June 2006 Current release: 5.1 (as of November 2009)
45Component Framework Primer
Tapestry Vision Similar separation of markup/logic Convention over Configuration Inversion of Control POJOs/annotations Performance
46Component Framework Primer
What is a Page? Markup lives in a .tml file Code/components live in a .java file Properties/messages in a .properties file TML files live in web root Other files on the class path All files for a page share a name
47Component Framework Primer
Saying Hello(Tapestry)
48Component Framework Primer
Grunge: web.xml
<filter>
<filter-name>tapestry</filter-name>
<filter-class>
org.apache.tapestry5.TapestryFilter
</filter-class>
</filter>
<filter-mapping>
<filter-name>tapestry</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter>
<filter-name>tapestry</filter-name>
<filter-class>
org.apache.tapestry5.TapestryFilter
</filter-class>
</filter>
<filter-mapping>
<filter-name>tapestry</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
49Component Framework Primer
Grunge: web.xml
<context-param>
<param-name>
tapestry.app-package
</param-name>
<param-value>
org.example.tapestry
</param-value>
</context-param>
<context-param>
<param-name>
tapestry.app-package
</param-name>
<param-value>
org.example.tapestry
</param-value>
</context-param>
50Component Framework Primer
My First Tapestry Page (TML)
<html xmlns:t="…">
<head><title>Hello, Tapestry!</title></head>
<body>
<!-- My first Tapestry component. -->
<!-- Note: We don't really need a component. -->
Hello, <t:textoutput t:value="name"/>!
</body>
</html>
<html xmlns:t="…">
<head><title>Hello, Tapestry!</title></head>
<body>
<!-- My first Tapestry component. -->
<!-- Note: We don't really need a component. -->
Hello, <t:textoutput t:value="name"/>!
</body>
</html>
51Component Framework Primer
My First Tapestry Page (Java)
public class Index {
@Property
private String name;
}
public class Index {
@Property
private String name;
}
52Component Framework Primer
Tapestry Rendering State machine/queue-based rendering
– No recursive component tree traversal
Components hook into rendering phases– SetupRender, BeginRender, BeforeRenderBody, etc.
Specified via annotations or naming conventions Hooks write response to MarkupWriter
– Streaming API with access to DOM-like structure
53Component Framework Primer
What Happens After Rendering? Persistent properties are state saved
– @Persist annotation identifes properties to persist
Page is cleaned up and returned to pool On postback, page instance retrieved from pool Persistent property values are restored Pooling is for performance (smaller footprint) Implies mostly static page structures
54Component Framework Primer
Take 2: t:id
55Component Framework Primer
Take 2: TML
<html xmlns:t="…">
<head><title>Hello, Tapestry!</title></head>
<body>
<!-- Does this seem familiar? -->
Hello,
<span t:id="nameOutput">Foo</span>!
</body>
</html>
<html xmlns:t="…">
<head><title>Hello, Tapestry!</title></head>
<body>
<!-- Does this seem familiar? -->
Hello,
<span t:id="nameOutput">Foo</span>!
</body>
</html>
56Component Framework Primer
Take 2: Java
public class Index {
@Property
private String name;
@Component(
parameters={"value=name"})
private TextOutput nameOutput;
}
public class Index {
@Property
private String name;
@Component(
parameters={"value=name"})
private TextOutput nameOutput;
}
57Component Framework Primer
Take 3: t:type
58Component Framework Primer
Take 3: TML
<html xmlns:t="…">
<head><title>Hello, Tapestry!</title></head>
<body>
Hello,
<span t:type="textoutput"
t:value="name">Foo</span>!
</body>
</html>
<html xmlns:t="…">
<head><title>Hello, Tapestry!</title></head>
<body>
Hello,
<span t:type="textoutput"
t:value="name">Foo</span>!
</body>
</html>
59Component Framework Primer
Facelets Flashback
<!-- Remember this? -->
<span jsfc="h:outputText"
value="#{name}">Foo</span>!
<!-- Remember this? -->
<span jsfc="h:outputText"
value="#{name}">Foo</span>!
60Component Framework Primer
Tapestry Property Expressions String notations for specifying object paths Similar to EL Supports referencing properties and methods Used for parameters and template expansions Compiled to Java classes (no reflection)
61Component Framework Primer
Property Expressions
<!-- Component parameter -->
<div><t:textoutput t:value="user.name"/></div>
<!-- Template expansion -->
<div>${user.name}</div>
<!-- Component parameter -->
<div><t:textoutput t:value="user.name"/></div>
<!-- Template expansion -->
<div>${user.name}</div>
62Component Framework Primer
Binding Expressions Parameters can bind to other types of values Prefix identifies binding type:
– prop– literal– asset– context– component– message
63Component Framework Primer
Binding Expressions
<!-- Property Binding-->
Hello, <t:textoutput t:value="name"/>!
<!-- Literal Binding-->
Hello, <t:textoutput t:value="literal:World"/>!
<!-- Property Binding-->
Hello, <t:textoutput t:value="name"/>!
<!-- Literal Binding-->
Hello, <t:textoutput t:value="literal:World"/>!
64Component Framework Primer
Some Initial Thoughts Key difference: declarative vs programmatic
component tree specification JSF favors declarative approach Wicket requires programmatic approach Tapestry is somewhere in the middle Component abstraction vs. direct access to HTML
65Component Framework Primer
Some More Thoughts Implicit per-page Java object is convenient Possible to simulate with JSF (viewScope bean) Consider formalizing this in JSF?
66Component Framework Primer
Event Handling
67Component Framework Primer
JSF Event Handling Inspired by Swing Event Model Listeners registered on components Components fire events Declarative: listeners referenced via EL
68Component Framework Primer
JSF Event Handling
<h:form>
<h:commandButton value="Increment"
actionListener="#{counter.increment}"/>
<h:outputText value="#{counter.count}"/>
</h:form>
<h:form>
<h:commandButton value="Increment"
actionListener="#{counter.increment}"/>
<h:outputText value="#{counter.count}"/>
</h:form>
69Component Framework Primer
JSF Event Handling
@ManagedBean
@SessionScoped
public class Counter {
public int getCount() { return count; }
public void increment() { count++; }
private int count;
}
@ManagedBean
@SessionScoped
public class Counter {
public int getCount() { return count; }
public void increment() { count++; }
private int count;
}
70Component Framework Primer
Wicket Event Handling
Components expose event-specific hooks Subclasses override to receive notifications
71Component Framework Primer
Wicket Event Handling
<form wicket:id="form">
<input type="submit" value="Increment"
wicket:id="button"/>
<span wicket:id="count">count</span>
</form>
<form wicket:id="form">
<input type="submit" value="Increment"
wicket:id="button"/>
<span wicket:id="count">count</span>
</form>
72Component Framework Primer
Wicket Event Handling
public class EventsPage extends WebPage {
public EventsPage() {
Button button = new Button("button") {
@Override
public void onSubmit() { count++; }
};
}
private int count;
}
public class EventsPage extends WebPage {
public EventsPage() {
Button button = new Button("button") {
@Override
public void onSubmit() { count++; }
};
}
private int count;
}
73Component Framework Primer
Wicket Event Handling onSubmit() exposed at both Button and Form level Button onSubmit() called first Link component provides form/POST-free events onClick() vs. onSubmit()
74Component Framework Primer
Tapestry Event Handling
Naming Conventions Annotations
75Component Framework Primer
Tapestry Event Handling
<t:form t:id="form1">
<input type="submit" value="Increment"
t:type="submit" t:id="button1"/>
${count}
</t:form>
<t:form t:id="form1">
<input type="submit" value="Increment"
t:type="submit" t:id="button1"/>
${count}
</t:form>
76Component Framework Primer
Tapestry Event Handling
public class Events {
@Persist
@Property
private int count;
// Called when any form is submitted
void onSubmit() { count++; }
}
public class Events {
@Persist
@Property
private int count;
// Called when any form is submitted
void onSubmit() { count++; }
}
77Component Framework Primer
Tapestry Event Handling
// All of these work too!
// Called when form 1 is submitted
void onSubmitFromForm1() { count++ }
// Called when any button is selected
void onSelected() { count++; }
// Called when button1 is selected
void onSelectedFromButton1() { count++; }
// All of these work too!
// Called when form 1 is submitted
void onSubmitFromForm1() { count++ }
// Called when any button is selected
void onSelected() { count++; }
// Called when button1 is selected
void onSelectedFromButton1() { count++; }
78Component Framework Primer
Tapestry Event Handling
// And these too
@OnEvent(value="selected", component="button1")void increment() { count++ }
@OnEvent(value="submit", component="form")void foo() { count++ }
// And these too
@OnEvent(value="selected", component="button1")void increment() { count++ }
@OnEvent(value="submit", component="form")void foo() { count++ }
79Component Framework Primer
Tapestry Event Handling
Component-specific events before form Global events before component-specific ActionLink provides form/POST-free events
80Component Framework Primer
Event Handling Wrap Up Three very different approaches Managed bean annotations simplify JSF approach Possible to add a Tapestry-like solution to JSF? Possible to add Wicket-like solution to JSF?
Programmatic component creation cases, yes. What about other cases?
Form-level submit hook is nice
81Component Framework Primer
Ajax
82Component Framework Primer
JSF Ajax Before: Take your pick
– ADF/Ice/Rich/Prime/Trinidad
Now: Standard Ajax APIs/implementation Ajax behaviors attached to components Primarily declarative solution Programmatic APIs available too
83Component Framework Primer
JSF Ajax
<h:form>
<h:commandButton value="Increment"
actionListener="#{counter.increment}">
<f:ajax render="count"/>
</h:commandButton>
<h:outputText value="#{counter.count}"
id="count"/>
</h:form>
<h:form>
<h:commandButton value="Increment"
actionListener="#{counter.increment}">
<f:ajax render="count"/>
</h:commandButton>
<h:outputText value="#{counter.count}"
id="count"/>
</h:form>
84Component Framework Primer
JSF Ajax
<f:ajax render="count"/>
<h:commandButton value="Increment"
actionListener="#{counter.increment}">
<h:commandButton value="Reset"
actionListener="#{counter.reset}">
</f:ajax>
<f:ajax render="count"/>
<h:commandButton value="Increment"
actionListener="#{counter.increment}">
<h:commandButton value="Reset"
actionListener="#{counter.reset}">
</f:ajax>
85Component Framework Primer
JSF Ajax All standard components support behaviors Attach points are component-specific
– Action, valueChange, focus, blur, mouse over, etc…
Behavior mechanism is extensible Not specific to Ajax
86Component Framework Primer
Wicket Ajax
Ajax Components Behaviors
87Component Framework Primer
Wicket Ajax
AjaxButton button = new AjaxButton("button") {
@Override
public void onSubmit(
AjaxRequestTarget target, Form form) {
count++;
if (target != null) {
target.addComponent(label);
}
}});
AjaxButton button = new AjaxButton("button") {
@Override
public void onSubmit(
AjaxRequestTarget target, Form form) {
count++;
if (target != null) {
target.addComponent(label);
}
}});
88Component Framework Primer
Wicket Ajax
label = new Label("count", …);
label.setOutputMarkupId(true);
label = new Label("count", …);
label.setOutputMarkupId(true);
89Component Framework Primer
Wicket Ajax Many convenience components, behaviors Fallback behavior: AjaxFallbackLink setOutputMarkupPlaceholderTag() Ajax debug window
90Component Framework Primer
Tapestry Ajax
Ajax Zones Mixins
91Component Framework Primer
Tapestry Ajax
<t:form t:id="form1" zone="countZone">
<input type="submit" value="Increment"
t:type="submit" t:id="button1"/>
<t:zone t:id="countZone">
Hello, ${count}
</t:zone>
</t:form>
<t:form t:id="form1" zone="countZone">
<input type="submit" value="Increment"
t:type="submit" t:id="button1"/>
<t:zone t:id="countZone">
Hello, ${count}
</t:zone>
</t:form>
92Component Framework Primer
Tapestry Ajax
public class Ajax {
@InjectComponent
private Zone countZone;
Object onSubmitFromForm1() {
return countZone.getBody();
}
}
public class Ajax {
@InjectComponent
private Zone countZone;
Object onSubmitFromForm1() {
return countZone.getBody();
}
}
93Component Framework Primer
Tapestry Ajax
Zone supported by Form, ActionLink, EventLink MultiZoneUpdate Mixins: autocomplete
94Component Framework Primer
Ajax Wrap Up JSF 2.0 Ajax is competitive with other solutions Wicket Ajax debug window is nice
– JSF implementations could provide equivalent
Improve JSF's fallback story? Resolve (or document) rendered toggling behavior
95Component Framework Primer
Navigation
96Component Framework Primer
JSF Navigation Traditional: POST-based navigation POST triggers action Action determines outcome Outcome mapped to target view
97Component Framework Primer
JSF Navigation
<h:commandButton action="#{nav.goToPageB}"/>
@ManagedBean(name="nav")
@RequestScoped
public class Navigation {
public String goToPageB() {
return "success";
}
}
<h:commandButton action="#{nav.goToPageB}"/>
@ManagedBean(name="nav")
@RequestScoped
public class Navigation {
public String goToPageB() {
return "success";
}
}
98Component Framework Primer
JSF Navigation
<navigation-rule>
<from-view-id>/pageA.xhtml</from-view-id>
<navigation-case>
<from-outcome>success</from-outcome>
<to-view-id>/pageB.xhtml</to-view-id>
<redirect/>
</navigation-case>
</navigation-rule>
<navigation-rule>
<from-view-id>/pageA.xhtml</from-view-id>
<navigation-case>
<from-outcome>success</from-outcome>
<to-view-id>/pageB.xhtml</to-view-id>
<redirect/>
</navigation-case>
</navigation-rule>
99Component Framework Primer
JSF Implicit Navigation Declarative navigation is good for many cases Perhaps too verbose for simple cases Implicit navigation simplifies simple cases Outcome implicitly treated as view id Bypasses faces-config.xml
100Component Framework Primer
JSF Implicit Navigation
<h:commandButton action="#{nav.goToPageB}"/>
@ManagedBean(name="nav")
@RequestScoped
public class Navigation {
public String goToPageB() {
// No faces-config entry required
return "pageB";
}
}
<h:commandButton action="#{nav.goToPageB}"/>
@ManagedBean(name="nav")
@RequestScoped
public class Navigation {
public String goToPageB() {
// No faces-config entry required
return "pageB";
}
}
101Component Framework Primer
JSF Pre-Emptive Navigation Implict navigation simplifies, but still POST-only Not GET/bookmark-friendly Pre-emptive navigation: best of both worlds Navigation rules aggressively evaluated <h:link>/<h:button> produce GET requests
102Component Framework Primer
JSF Pre-Emptive Navigation
<!-- Use navigation rules to determine "success" outcome target -->
<h:button outcome="success"/>
<!-- Both pre-emptive and implicit. No faces-config needed. -->
<h:button outcome="pageB"/>
<!-- Use navigation rules to determine "success" outcome target -->
<h:button outcome="success"/>
<!-- Both pre-emptive and implicit. No faces-config needed. -->
<h:button outcome="pageB"/>
103Component Framework Primer
Wicket Navigation
Programmatic navigation: setResponsePage() Class vs. instance
104Component Framework Primer
Wicket Navigation
Button button1 = new Button("button1") {
public void onSubmit() {
setResponsePage(PageB.class);
}
};
Button button1 = new Button("button1") {
public void onSubmit() {
setResponsePage(PageB.class);
}
};
105Component Framework Primer
Wicket Navigation
Button button1 = new Button("button1") {
public void onSubmit() {
PageB pageB = new PageB();
// Configure PageB instance…
setResponsePage(pageB);
}
};
Button button1 = new Button("button1") {
public void onSubmit() {
PageB pageB = new PageB();
// Configure PageB instance…
setResponsePage(pageB);
}
};
Wicket Navigation
106Component Framework Primer
Wicket Navigation
Direct navigation also supported BookmarkablePageLink wicket:link
107Component Framework Primer
Wicket Navigation
<!-- HTML -->
<a wicket:id="bookmarkable"
href="PageB.html">Navigate To Page B</a>
// Java
form.add(
new BookmarkablePageLink("bookmarkable",
PageB.class));
<!-- HTML -->
<a wicket:id="bookmarkable"
href="PageB.html">Navigate To Page B</a>
// Java
form.add(
new BookmarkablePageLink("bookmarkable",
PageB.class));
108Component Framework Primer
<!-- No Java code required. -->
<wicket:link>
<ul>
<li><a href="PageA.html">Page A</a></li>
<li><a href="PageB.html">Page B</a></li>
<li><a href="PageC.html">Page C</a></li>
<li><a href="PageD.html">Page D</a></li>
</ul>
</wicket:link>
<!-- No Java code required. -->
<wicket:link>
<ul>
<li><a href="PageA.html">Page A</a></li>
<li><a href="PageB.html">Page B</a></li>
<li><a href="PageC.html">Page C</a></li>
<li><a href="PageD.html">Page D</a></li>
</ul>
</wicket:link>
Wicket Navigation
109Component Framework Primer
Tapestry Navigation
Programmatic navigation: onSubmit() return Like Wicket, navigate to class or instance Instance page injected
110Component Framework Primer
Tapestry Navigation
public class PageA {
Object onSubmitFromForm1() {
return PageB.class;
}
}
public class PageA {
Object onSubmitFromForm1() {
return PageB.class;
}
}
111Component Framework Primer
Tapestry Navigation
public class PageA {
@InjectPage
private PageB pageB;
Object onSubmitFromForm1() {
// Configure pageB instance...
return pageB;
}
}
public class PageA {
@InjectPage
private PageB pageB;
Object onSubmitFromForm1() {
// Configure pageB instance...
return pageB;
}
}
112Component Framework Primer
Tapestry Navigation
Direct navigation also supported t:pageLink
113Component Framework Primer
Tapestry Navigation
<t:pagelink t:page="PageB">Go</t:pagelink><t:pagelink t:page="PageB">Go</t:pagelink>
114Component Framework Primer
Navigation Wrap Up JSF 2.0 enhancements simplify navigation String outcomes vs. class/instance Introduce class/instance support in JSF? Redirect defaults
115Component Framework Primer
Input Processing
116Component Framework Primer
JSF Input Processing EditableValueHolder lifecycle
– Decode– Conversion– Validation– Update model
Value referenced via value expression
117Component Framework Primer
JSF Input Processing
<h:inputText value="#{user.name}"/>
@ManagedBean
public class User {
public String getName() { return name; }
public void setName(String name) {
this.name = name;
}
private String name;
}
<h:inputText value="#{user.name}"/>
@ManagedBean
public class User {
public String getName() { return name; }
public void setName(String name) {
this.name = name;
}
private String name;
}
118Component Framework Primer
JSF Conversion Converters control transformation to/from string Attached to EditableValueHolder components Default conversion for most types Date/time and number converters for more control Custom converters
119Component Framework Primer
JSF Conversion
<h:inputText value="#{user.age}">
<f:convertNumber integerOnly="true"/>
</h:inputText>
<h:inputText value="#{user.age}">
<f:convertNumber integerOnly="true"/>
</h:inputText>
120Component Framework Primer
JSF Validation Validators verify converted value Attached to EditableValueHolder components Various standard validators provided with JSF Also possible to implement custom validators JSF 2.0 also applies JSR-303 validation constraints
121Component Framework Primer
JSF Validation
<h:inputText value="#{user.age}">
<f:validateLongRange minimum="18"/>
</h:inputText>
<h:inputText value="#{user.age}">
<f:validateLongRange minimum="18"/>
</h:inputText>
122Component Framework Primer
More JSF Validation Feedback
Typically displayed via <h:messages>/<h:message> More interesting feedback possible
Multi-component validation– Historically very tricky– PostValidate system event makes this much easier
Client-side validation– No out-of-box support– 3rd party solutions available (Trinidad/ADF Faces)
Ajax Validation– Facilitated by <f:ajax>
123Component Framework Primer
Wicket Input Processing Similar lifecycle to JSF
– Required field validation– Conversion– Validation– Push to model– onSubmit/onError
Value referenced via Model contract
124Component Framework Primer
Wicket Input Processing
<!-- HTML -->
<input type="text" wicket:id="firstName"/>
// Java
User user = getUser();
form.add(new TextField("firstName",
new PropertyModel(user, "name")));
<!-- HTML -->
<input type="text" wicket:id="firstName"/>
// Java
User user = getUser();
form.add(new TextField("firstName",
new PropertyModel(user, "name")));
125Component Framework Primer
Wicket Conversion IConverter contract, similar to JSF Converter Converts to/from string Default converters Type derived or hinted Custom converters
– Override getConverter()
126Component Framework Primer
Wicket Validation
IValidator, similar to JSF Validator Validators attached programmatically
127Component Framework Primer
Wicket Validation
<!-- HTML -->
<input type="text" wicket:id="age"/>
// Java
add(new TextField("age",
new PropertyModel(getUser(), "age"))
.add(NumberValidator.minimum(18)));
<!-- HTML -->
<input type="text" wicket:id="age"/>
// Java
add(new TextField("age",
new PropertyModel(getUser(), "age"))
.add(NumberValidator.minimum(18)));
128Component Framework Primer
More Wicket Validation Feedback
– FeedbackPanel (like h:messages)– FormComponentFeedbackBorder
Multi-component validation– IFormValidator
Client-side validation– No out-of-box support– Ajax validation preferred
Ajax Validation– AjaxFormValidatingBehavior
129Component Framework Primer
Tapestry Input Processing Similar lifecycle to JSF, Wicket
– Conversion– Validation– Push to model– onSuccess/onFailure
Value referenced via property expressions
130Component Framework Primer
Tapestry Input Processing
<!-- TML -->
<input type="text" t:type="textfield" t:value="user.name"/>
// Java
public class Input {
@Property
private User user;
}
<!-- TML -->
<input type="text" t:type="textfield" t:value="user.name"/>
// Java
public class Input {
@Property
private User user;
}
131Component Framework Primer
Tapestry Conversion
FieldTranslator, similar to Converter/IConverter Event-based conversion
– toclient– parseclient
132Component Framework Primer
Tapestry Conversion Events
public class Input {
String onToClientFromAge() {
// Return String representation of age
}
Object onParseClientFromAge(String input) {
// Return converted representation of age
}
}
public class Input {
String onToClientFromAge() {
// Return String representation of age
}
Object onParseClientFromAge(String input) {
// Return converted representation of age
}
}
133Component Framework Primer
Tapestry Validation
FieldValidator, similar to Validator/Ivalidator Constraints attached via component parameters Event and annotation-based validation
134Component Framework Primer
Parameter-Based Validation
<input type="text" t:type="textfield"
t:value="user.age"
t:validate="required,min=18"/>
<input type="text" t:type="textfield"
t:value="user.age"
t:validate="required,min=18"/>
135Component Framework Primer
Event-Based Validation
void onValidateFromAge(Integer value)
throws ValidationException
{
if (value < 18)
throw new ValidationException("Too young!");
}
void onValidateFromAge(Integer value)
throws ValidationException
{
if (value < 18)
throw new ValidationException("Too young!");
}
136Component Framework Primer
Anntation-Based Validation
public class Input { @Property @Validate("required,min=18") private int age;}
public class Input { @Property @Validate("required,min=18") private int age;}
137Component Framework Primer
More Tapestry Validation Feedback
– Border highlight, hover text– <t:errors>
Multi-component validation– onValidateForm()
Client-side validation– Provided automatically for standard validators
Ajax Validation– Client-side validation preferred
138Component Framework Primer
Input Processing Wrap Up Similar input processing across frameworks
– Surprise?
Pull client-side validation into JSF? Improve feedback reporting Encourage use of PostValidate system event for
multi-component validation
139Component Framework Primer
Custom Components
140Component Framework Primer
JSF: Old School (Java) Java class (extends UIComponent) Renderer class Tag class faces-config.xml tld
141Component Framework Primer
JSF: New School (Java)
Annotations replace faces-cofig.xml Default Facelets handlers replace Tag class taglib.xml replaces tld
142Component Framework Primer
JSF: New School (Composite) Single Facelets file defines composite component Installed in resources directory Component namespace/name derived No external configuration Optional Java component class Optional properties file
143Component Framework Primer
resources/demo/titleBorder.xhtml<html ... ><body>
<composite:implementation>
<div class="tb-root">
<div class="tb-title">#{cc.attrs.title}</div>
<div class="tb-body">
<composite:insertChildren/>
</div>
</div>
</composite:implementation>
</body></html>
<html ... ><body>
<composite:implementation>
<div class="tb-root">
<div class="tb-title">#{cc.attrs.title}</div>
<div class="tb-body">
<composite:insertChildren/>
</div>
</div>
</composite:implementation>
</body></html>
144Component Framework Primer
Composite Interface
<composite:interface> <composite:attribute name="title" required="true"/></composite:interface>
<composite:interface> <composite:attribute name="title" required="true"/></composite:interface>
145Component Framework Primer
Component Usage
<html … xmlns:demo=
"http://java.sun.com/jsf/composite/demo">
<body>
<demo:titleBorder title="My Favorite Greeting">
Hello, World!
</demo:titleBorder>
</body>
</html>
<html … xmlns:demo=
"http://java.sun.com/jsf/composite/demo">
<body>
<demo:titleBorder title="My Favorite Greeting">
Hello, World!
</demo:titleBorder>
</body>
</html>
146Component Framework Primer
Wicket Custom Components We have already seen several custom components
– Think event handling
Can also define components with custom markup Very similar to page HTML/Java split Java extends Panel or Border (not WebPage)
147Component Framework Primer
TitleBorder.html<html ... ><body>
<wicket:border>
<div class="tb-root">
<div class="tb-title"
wicket:id="titleLabel">Title</div>
<div class="tb-body">
<wicket:body/>
</div>
</div>
</wicket:border>
</body></html>
<html ... ><body>
<wicket:border>
<div class="tb-root">
<div class="tb-title"
wicket:id="titleLabel">Title</div>
<div class="tb-body">
<wicket:body/>
</div>
</div>
</wicket:border>
</body></html>
148Component Framework Primer
TitleBorder.javapublic class TitleBorder extends Border {
public TitleBorder(String id) {
super(id);
add(new Label("titleLabel",
new PropertyModel(this, "title")));
}
// Accessors
private String title;
}
public class TitleBorder extends Border {
public TitleBorder(String id) {
super(id);
add(new Label("titleLabel",
new PropertyModel(this, "title")));
}
// Accessors
private String title;
}
149Component Framework Primer
Component Usage
<!-- HTML -->
<div wicket:id="titleBorder">
Hello, World!
</div>
// Java
add(new TitleBorder("titleBorder"));
<!-- HTML -->
<div wicket:id="titleBorder">
Hello, World!
</div>
// Java
add(new TitleBorder("titleBorder"));
150Component Framework Primer
Tapestry Custom Components Again, similar to page TML/Java split Java component is a POJO Located in app-package/components directory
151Component Framework Primer
TitleBorder.tml
<div class="tb-root" ... >
<div class="tb-title">${title}</div>
<div class="tb-body">
<t:body/>
</div>
</div>
<div class="tb-root" ... >
<div class="tb-title">${title}</div>
<div class="tb-body">
<t:body/>
</div>
</div>
152Component Framework Primer
TitleBorder.java
public class TitleBorder {
@Property
@Parameter(required=true,
defaultPrefix=BindingConstants.LITERAL)
private String title;
}
public class TitleBorder {
@Property
@Parameter(required=true,
defaultPrefix=BindingConstants.LITERAL)
private String title;
}
153Component Framework Primer
Component Usage
<t:titleborder t:title="My Favorite Greeting">
Hello, World!
</t:titleborder>
<t:titleborder t:title="My Favorite Greeting">
Hello, World!
</t:titleborder>
154Component Framework Primer
Custom Component Wrap Up JSF custom component development became
much, much simpler in 2.0 Composite components provide ease of use
previously only available in other frameworks Further simplifications possible?
– Composite components– Java-based components
155Component Framework Primer
Wrap Up
156Component Framework Primer
So Much To Do, So Little Time Many other possible points of comparison
– Performance– Tooling– Testing– I18N– Persistence– REST– Extensions– Community
Other interesting frameworks too! Presentation 2.0 :-)
157Component Framework Primer
Conclusion Some differences are fundamental Interesting to see many similarities too Looking outward: good exercise Good to see historical areas of difficulty addressed
by JSF 2.0. JSF2.next: Keep the progress coming!