You are on page 1of 47

Apache Wicket – keep it

simple!

Baruch Sadogursky
Consultant & Architect,
AlphaCSP

2
Copyright AlphaCSP Israel 2008 – Web Framework Playoff Seminar
Agenda

• Introduction
• Framework features
• Summary

3
Copyright AlphaCSP Israel 2008 – Web Framework Playoff Seminar
Introduction

4
Copyright AlphaCSP Israel 2008 – Web Framework Playoff Seminar
Intro::Wicket

• “Wicket” means “gate”


• Cricket
• Small door inside a big gate
• Wicket W. Warrick
• Star Wars character
• Why “Wicket”?
• Unique, memorable, easy and not taken
• “Wik-it”
• Lightweight wicket in immovable J2EE gate

5
Copyright AlphaCSP Israel 2008 – Web Framework Playoff Seminar
Intro::Apache Wicket

• Component–oriented
• Open Source
• Write HTML (HTML style)
• Write Java (Swing style)
• Tie them together through IDs

6
Copyright AlphaCSP Israel 2008 – Web Framework Playoff Seminar
Intro::Hello, World!

1 public class HelloWorld extends WebPage {


2 public HelloWorld() {
3 add(new Label("message", "Hello, World!"));
4 }
5 }
+
1 <html>
2 <body>
3 <h1 wicket:id="message">Hello, World!</h1>
4 </body>
5 </html>
=
1 <html>
2 <body>
3 <h1 wicket:id="message">Hello, World!</h1>
4 </body>
5 </html>

7
Copyright AlphaCSP Israel 2008 – Web Framework Playoff Seminar
Intro::Looks Familiar?

Wicket:
1 public class HelloWorld extends WebPage {
2 public HelloWorld() {
3 add(new Label("message", "Hello, World!"));
4 }
5 }

Swing:
1 public class HelloWorld extends JFrame {
2 public HelloWorld() {
3 add(new Label("Hello, World!"));
4 }
5 }

8
Copyright AlphaCSP Israel 2008 – Web Framework Playoff Seminar
Intro::History

Mar-04
Jonathan Locke envisioned and originated Wicket
Jun-05 Mar-06 Jul-07 Jan-08 Jun-08
May-05 Wicket 1.0 final Wicket 1.2 released Apache Wicket Wicket 1.3 released Wicket 1.4 m2
JavaOne presentation

Apr-04 Jul-04 Oct-04 Jan-05 Apr-05 Jul-05 Oct-05 Jan-06 Apr-06 Jul-06 Oct-06 Jan-07 Apr-07 Jul-07 Oct-07 Jan-08 Apr-08

Mar-04 Jun-08

9
Copyright AlphaCSP Israel 2008 – Web Framework Playoff Seminar
Intro::Wicket Hype

10
Copyright AlphaCSP Israel 2008 – Web Framework Playoff Seminar
Intro::Concepts – Component

• Building block of the application


• Renders itself
• Receives events
• More than 220 components in Wicket
core & Wicket extensions
• Easily extendable (customizable)

11
Copyright AlphaCSP Israel 2008 – Web Framework Playoff Seminar
Intro:: Concepts – Components

Swing Wicket
awt.Component
Component

awt.Container
WebComponent MarkupContainer

awt.Window JContainer

Label Page WebMarkupContainer

awt.Frame JComponent

WebPage Panel Link


JFrame JPanel JLabel JButton

12
Copyright AlphaCSP Israel 2008 – Web Framework Playoff Seminar
Intro::Concepts – Model

• No property binding in Java (for now)


• Wraps Object, which component renders
• Basic models for single object
• Property models for properties
• EL like expressions
• Exactly as Swing Models
1 private IColumn[] getTableColumns() {
2 List<IColumn> columns = new ArrayList<IColumn>();
3 columns.add(new PropertyColumn(new ResourceModel("name"), "name", "name"));
4 columns.add(new PropertyColumn(new ResourceModel("department.name"), "department.name"));
5 columns.add(new TextFieldColumn(new ResourceModel("email"), "email"));
6 return columns.toArray(new IColumn[columns.size()]);
7 }
1 public LoginForm(MarkupContainer parent) {
2 super("loginForm", new CompoundPropertyModel(new User()));
3 parent.add(this);
4 add(new TextField("username").setRequired(true));
5 PasswordTextField passwordTextField = new PasswordTextField("password");
6 passwordTextField.setRequired(true);
7 add(passwordTextField);
8 …
9 }

13
Copyright AlphaCSP Israel 2008 – Web Framework Playoff Seminar
Intro::Concepts – Behavior

• Plugin to the component


• Gets component lifecycle events and
can react by changing the generated
HTML
• Example
• SimpleAttributeModifier changes
HTML tag attributes on render

14
Copyright AlphaCSP Israel 2008 – Web Framework Playoff Seminar
Intro::Concepts

• Application
• Configure and init
• Example later
• Session
• Strongly typed HTTP session wrapper
• RequestCycle
• Represents the processing of a request
• Tells RequestCycleProcessor what to do
• How to handle events
• How to generate response

15
Copyright AlphaCSP Israel 2008 – Web Framework Playoff Seminar
Wicket Features Review

16
Copyright AlphaCSP Israel 2008 – Web Framework Playoff Seminar
Features::Configuration

• No Wicket XML files


• Convention over configuration
• Configuration done in Java
• Spring integration
• Just enable injecting interceptor
1 @SpringBean
1 protected void init() { 2 private UserService userService;
2 super.init();
3 addComponentInstantiationListener(new SpringComponentInjector(this));
4 getResourceSettings().setThrowExceptionOnMissingResource(true);
5 mountBookmarkablePage("hello_world.html", HelloWorld.class);
6 }
7
8 @Override
9 public Class getHomePage() {
10 return SearchPage.class;
11 }

17
Copyright AlphaCSP Israel 2008 – Web Framework Playoff Seminar
Features::View Technology

• Valid XHTML
• No custom markup (almost)
• wicket:id attribute
• The only mandatory one
• <wicket:message/> resource bundle
lookup
• See I18N

18
Copyright AlphaCSP Israel 2008 – Web Framework Playoff Seminar
Features::View Technology

• Reuse HTML as it was Java


• <wicket:child/>
• <wicket:extend/>
• <wicket:panel/>
1 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
2 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
3 <?xml version="1.0" encoding="UTF-8"?>
4 <html xmlns="http://www.w3.org/1999/xhtml" xmlns:wicket="http://wicket.apache.org/">
5 <head>
6 …
11 </head>
12 <body>
13 <wicket:child/>
14 </body>
15 </html>

1 <wicket:extend>
2 <div align="right" class="header" wicket:id="welcomePanel"></div>
3 <div class="phoneBook" align="center" wicket:id="searchPanel"></div>
4 <div class="phoneBook" align="center" wicket:id="resultsPanel"></div>
5 </wicket:extend>

19
Copyright AlphaCSP Israel 2008 – Web Framework Playoff Seminar
Features::View Technology

• Reuse HTML as it was Java


• <wicket:child/>
• <wicket:extend/>
• <wicket:panel/>
1 <wicket:extend>
2 <div align="right" class="header" wicket:id="welcomePanel"></div>
3 <div class="phoneBook" align="center" wicket:id="searchPanel"></div>
4 <div class="phoneBook" align="center" wicket:id="resultsPanel"></div>
5 </wicket:extend>

1 <wicket:panel>
2 <table>
3 <tr>
4 <td class="header"><wicket:message key="user"/>: <span wicket:id="username"></span></td>
5 <td class="headerSeperator">|</td>
6 <td class="header"><a href="#" wicket:id="logout"><wicket:message key="logout"/></a></td>
7 </tr>
8 </table>
9 </wicket:panel>

20
Copyright AlphaCSP Israel 2008 – Web Framework Playoff Seminar
Features::Page Flow

• Inside onSubmit (buttons, links and


forms)
• setResponsePage(SomePage.class);
• setResponsePage(somePage);
1 @Override
2 protected void onSubmit() {
3 User credentials = (User) this.getModelObject();
4 WicketSession session = WicketSession.get();
5 User loggedInUser = userService.login(credentials);
6 if (loggedInUser != null) {
7 session.setUser(loggedInUser);
8 setResponsePage(SearchPage.class);
9 } else {
10 this.error("Sorry, …");
11 setModelObject(new User());
12 }
13 }

21
Copyright AlphaCSP Israel 2008 – Web Framework Playoff Seminar
Features::Form Binding

• Form is a component
• So, it is backed up with model
1 private SearchForm(MarkupContainer parent) {
2 super("searchForm", new CompoundPropertyModel(new Contact()));
3 parent.add(this);
4 add(new TextField("name"));
5 TextField emailTextField = new TextField("email");
6 emailTextField.add(EmailAddressValidator.getInstance());
7 add(emailTextField);
8 …
9 }

22
Copyright AlphaCSP Israel 2008 – Web Framework Playoff Seminar
Features::Table Sorting

• Headers should be added to table


• Property expression is optionally
passed when constructing Column
• If passed – the header will be clickable
1 private static class SortablePagedDataTable extends DataTable {
2 private SortablePagedDataTable(String id, IColumn[] tableColumns,
3 ContactsListDataProvider contacts, int rowsPerPage) {
4 super(id, tableColumns, contacts, rowsPerPage);
5 addTopToolbar(new AjaxFallbackHeadersToolbar(this, contacts));
6 addBottomToolbar(new AjaxNavigationToolbar(this));
7 }
8 }
1 private IColumn[] getTableColumns() {
2 List<IColumn> columns = new ArrayList<IColumn>();
3 columns.add(new PropertyColumn(new ResourceModel("name"), "name", "name"));
4 columns.add(new PropertyColumn(new ResourceModel("department.name"), "department.name"));
5 columns.add(new TextFieldColumn(new ResourceModel("email"), "email"));
6 return columns.toArray(new IColumn[columns.size()]);
7 }
8

23
Copyright AlphaCSP Israel 2008 – Web Framework Playoff Seminar
Features::Table Sorting

• You generate the displayed data


• So, you are in charge of actual sorting
• Property expression and sort
direction is provided
1 public class ContactsListDataProvider extends SortableDataProvider {
2 …
3 public Iterator<Contact> iterator(int first, int count) {
4 List<Contact> sublist = data.subList(first, first + count);
5 SortParam sort = getSort();
6 if (sort != null && "name".equals(sort.getProperty())) {
7 Collections.sort(sublist);
8 if (!sort.isAscending()) {
9 Collections.reverse(sublist);
10 }
11 }
12 return sublist.iterator();
13 }

24
Copyright AlphaCSP Israel 2008 – Web Framework Playoff Seminar
Features::Pagination

• Navigation toolbar should be added


to table (top or bottom)
• Rows per page count is passed in the
constructor
1 private static class SortablePagedDataTable extends DataTable {
2 private SortablePagedDataTable(String id, IColumn[] tableColumns,
3 ContactsListDataProvider contacts, int rowsPerPage) {
4 super(id, tableColumns, contacts, rowsPerPage);
5 addTopToolbar(new AjaxFallbackHeadersToolbar(this, contacts));
6 addBottomToolbar(new AjaxNavigationToolbar(this));
7 }
8 }

1 public ResultsPanel(ContactsListDataProvider contactsDataProvider) {


2 super("resultsPanel");
3 DataTable contactsTable = new SortablePagedDataTable("contactsTable",
4 getTableColumns(), contactsDataProvider, 10);
5 add(contactsTable);
6 }

25
Copyright AlphaCSP Israel 2008 – Web Framework Playoff Seminar
Features::Pagination

• You generate the displayed data


• So, you are in charge of actual
sublisting
• First and count are provided
1 public class ContactsListDataProvider extends SortableDataProvider {
2 …
3 public Iterator<Contact> iterator(int first, int count) {
4 List<Contact> sublist = data.subList(first, first + count);
5 SortParam sort = getSort();
6 if (sort != null && "name".equals(sort.getProperty())) {
7 Collections.sort(sublist);
8 if (!sort.isAscending()) {
9 Collections.reverse(sublist);
10 }
11 }
12 return sublist.iterator();
13 }

26
Copyright AlphaCSP Israel 2008 – Web Framework Playoff Seminar
Features::Validations (Server)

• “Required” validation – just say


• Validation errors added to their own
<div> (css it at will)
1 public LoginForm(MarkupContainer parent) {
2 super("loginForm", new CompoundPropertyModel(new User()));
3 parent.add(this);
4 add(new TextField("username").setRequired(true));
5 PasswordTextField passwordTextField = new PasswordTextField("password");
6 passwordTextField.setRequired(true);
7 add(passwordTextField);
8 FeedbackPanel feedbackPanel = new FeedbackPanel("feedback");
9 feedbackPanel.setEscapeModelStrings(false);
10 add(feedbackPanel);
11 }

1 <tr>
2 <td colspan="2" class="feedback" wicket:id="feedback"/>
3 </tr>

27
Copyright AlphaCSP Israel 2008 – Web Framework Playoff Seminar
Features::Validations (Server)

• Other validations – add Validators to


the components
• 24 ready validators in wicket-core and
wicket-extensions

1 private SearchForm(MarkupContainer parent) {


2 super("searchForm", new CompoundPropertyModel(new Contact()));
3 parent.add(this);
4 add(new TextField("name"));
5 TextField emailTextField = new TextField("email");
6 emailTextField.add(EmailAddressValidator.getInstance());
7 …
12 }

28
Copyright AlphaCSP Israel 2008 – Web Framework Playoff Seminar
Features::Validations (Client)

• Server validations are must


• Target of client validation – provide
earlier feedback to the user
• Client validations should be copy of
Java code in JS
• No automatic JS port for server-side
validations (only Google can?)

29
Copyright AlphaCSP Israel 2008 – Web Framework Playoff Seminar
Features::Validations (Client)

• Solution – call server-side validations


in AJAX
• Same experience for the user
• Slower on slow connections

1 private SearchForm(MarkupContainer parent) {


2 super("searchForm", new CompoundPropertyModel(new Contact()));
3 parent.add(this);
4 add(new TextField("name"));
5 TextField emailTextField = new TextField("email");
6 emailTextField.add(EmailAddressValidator.getInstance());
7 …
8 AjaxFormValidatingBehavior.addToAllFormComponents(this, "onblur");
9 }

30
Copyright AlphaCSP Israel 2008 – Web Framework Playoff Seminar
Features::AJAX

• Use AJAX components instead of


non-AJAX ones
• Add components to be refreshed
1 private SearchForm(MarkupContainer parent) {
2 super("searchForm", new CompoundPropertyModel(new Contact()));
3 parent.add(this);
4 …
12 add(new AjaxButton("submit", this){
13
14 @Override
15 protected void onSubmit(AjaxRequestTarget target, Form form) {
16 Contact exampleContact = (Contact) SearchForm.this.getModelObject();
17 List<Contact> contacts = companyService.findContactsByExample(exampleContact);
18 contactsDataProvider.setData(contacts);
19 ResultsPanel resultsPanel = ((SearchPage) getPage()).getResultsPanel();
20 target.addComponent(resultsPanel);
21 }
22 });
23 AjaxFormValidatingBehavior.addToAllFormComponents(this, "onblur");
24 }

31
Copyright AlphaCSP Israel 2008 – Web Framework Playoff Seminar
Features::AJAX

• JS is generated using Dojo and


Script.aculo.us
• Automatic fallback to non-js
components
1 <script type="text/javascript"
2 src="resources/org.apache.wicket.markup.html.WicketEventReference/wicket-event.js">
3 </script>
4 <script type="text/javascript"
5 src="resources/org.apache.wicket.ajax.WicketAjaxReference/wicket-ajax.js">
6 </script>
7 <script type="text/javascript"
8 src="resources/org.apache.wicket.ajax.AbstractDefaultAjaxBehavior/wicket-ajax-debug.js">
9 </script>
10 <script type="text/javascript"
11 id="wicket-ajax-debug-enable"><!--/*--><![CDATA[/*><!--*/
12 wicketAjaxDebugEnable = true;
13 /*-->]]>*/</script>
14 <script type="text/javascript"
15 src="resources/org.apache.wicket.extensions.ajax.markup.html.autocomplete.AutoCompleteBehavior/wicket-autocomplete.js">
16 </script>
17 <script type="text/javascript"><!--/*--><![CDATA[/*><!--*/
18 Wicket.Event.add(window, "domready", function() {
19 new Wicket.AutoComplete('department2',
20 '?wicket:interface=:2:searchPanel:searchForm:department::IActivePageBehaviorListener:1:&wicket:ignoreIfNotActive=true',
21 false);
22 });
23 /*-->]]>*/</script>

32
Copyright AlphaCSP Israel 2008 – Web Framework Playoff Seminar
Features::AJAX

• Great debug utility

33
Copyright AlphaCSP Israel 2008 – Web Framework Playoff Seminar
Features::Error Handling – Dev

• Very self-explanatory error pages

34
Copyright AlphaCSP Israel 2008 – Web Framework Playoff Seminar
Features::Error Handling – Prod

• Application level config of different kinds of errors


1 private void initExceptionHandeling() {
2 IApplicationSettings appSettings = getApplicationSettings();
3 appSettings.setPageExpiredErrorPage(PageExpiredErrorPage.class);
4 appSettings.setAccessDeniedPage(AccessDeniedPage.class);
5 appSettings.setInternalErrorPage(InternalErrorPage.class);
6 getExceptionSettings().setUnexpectedExceptionDisplay(SHOW_INTERNAL_ERROR_PAGE);
7 }

• Per page configuration


1 @Override
2 protected void onSubmit(AjaxRequestTarget target, Form form) {
3 Contact exampleContact = (Contact) SearchForm.this.getModelObject();
4 try {
5 List<Contact> contacts = companyService.findContactsByExample(exampleContact);
6 contactsDataProvider.setData(contacts);
7 ResultsPanel resultsPanel = ((SearchPage) getPage()).getResultsPanel();
8 target.addComponent(resultsPanel);
9 } catch (RuntimeException e) {
10 getRequestCycle().onRuntimeException(new SearchErrorPage(e), e);
11 }
12 }

35
Copyright AlphaCSP Israel 2008 – Web Framework Playoff Seminar
Features::Error Handling – Prod

• onRuntimeException override in
RequestCycle
• In this case you get the actual
exception object
1 @Override
2 public RequestCycle newRequestCycle(Request request, Response response) {
3 return new WebRequestCycle(this, (WebRequest) request, response) {
4
5 @Override
6 public Page onRuntimeException(Page page, RuntimeException e) {
7 return new InternalErrorPage(e);
8 }
9 };
10 }

36
Copyright AlphaCSP Israel 2008 – Web Framework Playoff Seminar
Features::I18N Support

• Full I18N of all the application using


Resource bundles
• Use <wicket:message key=“…"/>
instead of hard-coded text
1 page.title= 1 page.title=Login
2 username= 2 username=<u>U</u>sername
3 password= 3 password=<u>P</u>assword
4 submit= 4 submit=Login

1 <tr>
2 <td valign=middle align=right width=25%><b><wicket:message key="username"/></b></td>
3 <td valign=middle>
4 <input class="loginField" type="text" id="username" size="25" tabindex=1
5 accessKey="u" wicket:id="username">
6 </td>
7 </tr>

37
Copyright AlphaCSP Israel 2008 – Web Framework Playoff Seminar
Features::L10N Support

• Use “HTML Bundles”


• Similar to resource bundles, but for HTML pages
• LoginPage.html – default
• LoginPage_iw.html – right-to-left
1 public WicketSession(Request request) {
2 super(request);
3 setLocale(new Locale("iw"));
4 }

1 <table class="loginTable" border="1" style="direction: rtl;">


2 <tr>
3 …
4 </tr>
5 </table>

38
Copyright AlphaCSP Israel 2008 – Web Framework Playoff Seminar
Features:: Documentation

• Source
• API documentation
• Nabble
• Forum & Mailing List
• Books
• Pro Wicket
• Wicket in Action
• Early Access available, in print next month
• Sites (see References)
39
Copyright AlphaCSP Israel 2008 – Web Framework Playoff Seminar
Summary

40
Copyright AlphaCSP Israel 2008 – Web Framework Playoff Seminar
Summary

Feature Summary
Configuration No XML! 
View technology Valid XHTML  Cut to pieces 
Page flow No XML! 
Form binding Swing-like models 
Table sorting Eeeeasy 
Pagination Eeeeasy 
Validations No JS generation 
AJAX Eeeeasy, but JS can be better 
Error handling Powerful and configurable 
I18n support Java resource bundles 
Documentation Tons, can be organized better 

41
Copyright AlphaCSP Israel 2008 – Web Framework Playoff Seminar
Summary::Java!

• Fast learning curve


• MVC at component level
• Truly object oriented
• Code centric
• Trivial component creation
• Java FWs integration
• Full debuggability

42
Copyright AlphaCSP Israel 2008 – Web Framework Playoff Seminar
Summary::Cons

• Internals are complex


• The API is too big
• No structured “Best Practices”
• Documentation is a mess
• Java limitations
• Anonymous classes instead of closures
• Generics troubles

43
Copyright AlphaCSP Israel 2008 – Web Framework Playoff Seminar
Summary::Cons

• A lot of Java code required


• Maintainability
• No generics support in API (until 1.4)
• No automatic client-side validation
generation
• Not suitable for very dynamic pages
• HTML cut between different files
• Not so comfortable for HTML coders

44
Copyright AlphaCSP Israel 2008 – Web Framework Playoff Seminar
Summary::The Future

• Wicket 1.4
• Generics
• Model<T>
• Component<T>
• M2 is available
• Wicket 1.5
• Multiple extend/child areas
• Proxy Model
• Strongly typed properties
• Tabbed browsers support
• Many more

45
Copyright AlphaCSP Israel 2008 – Web Framework Playoff Seminar
Summary:: References

• wicket.apache.org
• cwiki.apache.org/WICKET
• wicketstuff.org
• www.wicket-library.com
• issues.apache.org/jira/browse/WICKET

46
Copyright AlphaCSP Israel 2008 – Web Framework Playoff Seminar
Thank
You!
47
Copyright AlphaCSP Israel 2008 – Web Framework Playoff Seminar

You might also like