Wicket 6 Reference Guide

User Manual: Pdf

Open the PDF directly: View PDF PDF.
Page Count: 220

DownloadWicket-6-reference-guide
Open PDF In BrowserView PDF
Free Online Guide for Apache Wicket framework

Apache Wicket User Guide Reference Documentation
Authors: Andrea Del Bene, Martin Grigorov, Carsten Hufe, Christian Kroemer, Daniel Bartl, Paul Bor, Tobias
Soloschenko, Joachim Rohde
Version: 6.x

Table of Contents
1 Introduction
2 How to use the example code
3 Why should I learn Wicket?
3.1 We all like spaghetti :-) ...
3.2 Component oriented frameworks - an overview
3.3 Benefits of component oriented frameworks for web development
3.4 Wicket vs the other component oriented frameworks
4 Wicket says Hello world!
4.1 Wicket distribution and modules
4.2 Configuration of Wicket applications
4.3 The HomePage class
4.4 Wicket Links
4.5 Summary
5 Wicket as page layout manager
5.1 Header, footer, left menu, content, etc...
5.2 Here comes the inheritance!
5.3 Divide et impera!
5.4 Markup inheritance with the wicket:extend tag
5.5 Summary
6 Keeping control over HTML
6.1 Hiding or disabling a component
6.2 Modifing tag attributes
6.3 Generating tag attribute 'id'
6.4 Creating in-line panels with WebMarkupContainer
6.5 Working with markup fragments
6.6 Adding header contents to the final page
6.7 Using stub markup in our pages/panels

1

6.8 How to render component body only
6.9 Hiding decorating elements with the wicket:enclosure tag
6.10 Surrounding existing markup with Border
6.11 Summary
7 Components lifecycle
7.1 Lifecycle stages of a component
7.2 Hook methods for component lifecycle
7.3 Initialization stage
7.4 Rendering stage
7.5 Removing stage
7.6 Summary
8 Page versioning and caching
8.1 Stateful pages vs stateless
8.2 Stateful pages
8.3 Stateless pages
8.4 Summary
9 Under the hood of the request processing
9.1 Class Application and request processing
9.2 Request and Response classes
9.3 The director of request processing - RequestCycle
9.4 Session Class
9.5 Exception handling
9.6 Summary
10 Wicket Links and URL generation
10.1 PageParameters
10.2 Bookmarkable links
10.3 Automatically creating bookmarkable links with tag wicket:link
10.4 External links
10.5 Stateless links
10.6 Generating structured and clear URLs
10.7 Summary
11 Wicket models and forms
11.1 What is a model?
11.2 Models and JavaBeans
11.3 Wicket forms
11.4 Component DropDownChoice
11.5 Model chaining
11.6 Detachable models
11.7 Using more than one model in a component
11.8 Use models!
11.9 Summary
12 Wicket forms in detail

2

12.1 Default form processing
12.2 Form validation and feedback messages
12.3 Input value conversion
12.4 Validation with JSR 303
12.5 Submit form with an IFormSubmittingComponent
12.6 Nested forms
12.7 Multi-line text input
12.8 File upload
12.9 Creating complex form components with FormComponentPanel
12.10 Stateless form
12.11 Working with radio buttons and checkboxes
12.12 Selecting multiple values with ListMultipleChoices and Palette
12.13 Summary
13 Displaying multiple items with repeaters
13.1 The RepeatingView Component
13.2 The ListView Component
13.3 The RefreshingView Component
13.4 Pageable repeaters
13.5 Summary
14 Internationalization with Wicket
14.1 Localization
14.2 Localization in Wicket
14.3 Bundles lookup algorithm
14.4 Localization of component's choices
14.5 Internationalization and Models
14.6 Summary
15 Resource management with Wicket
15.1 Static vs dynamic resources
15.2 Resource references
15.3 Package resources
15.4 Adding resources to page header section
15.5 Context-relative resources
15.6 Resource dependencies
15.7 Aggregate multiple resources with resource bundles
15.8 Put JavaScript inside page body
15.9 Header contributors positioning
15.10 Custom resources
15.11 Mounting resources
15.12 Shared resources
15.13 Customizing resource loading
15.14 CssHeaderItem and JavaScriptHeaderItem compression
15.15 Summary

3

16 An example of integration with JavaScript
16.1 What we want to do...
16.2 ...and how we will do it
16.3 Summary
17 Wicket advanced topics
17.1 Enriching components with behaviors
17.2 Generating callback URLs with IRequestListener
17.3 Initializers
17.4 Using JMX with Wicket
17.5 Generating HTML markup from code
17.6 Summary
18 Working with AJAX
18.1 How to use AJAX components and behaviors
18.2 Build-in AJAX components
18.3 Built-in AJAX behaviors
18.4 Using an activity indicator
18.5 AJAX request attributes and call listeners
18.6 Creating custom AJAX call listener
18.7 Summary
19 Integration with enterprise containers
19.1 Integrating Wicket with EJB
19.2 Integrating Wicket with Spring
19.3 JSR-330 annotations
19.4 Summary
20 Native WebSockets
20.1 How does it work ?
20.2 How to use
20.3 Client-side APIs
20.4 Testing
20.5 Differences with Wicket-Atmosphere module.
20.6 FAQ
21 Security with Wicket
21.1 Authentication
21.2 Authorizations
21.3 Using HTTPS protocol
21.4 URLs encryption in detail
21.5 Package Resource Guard
21.6 Summary
22 Test Driven Development with Wicket
22.1 Utility class WicketTester
22.2 Testing Wicket forms
22.3 Testing markup with TagTester

4

22.4 Summary
23 Test Driven Development with Wicket and Spring
23.1 Configuration of the runtime environment
23.2 Configuration of the JUnit based integration test environment
23.3 Summary
24 Wicket Best Practices
24.1 Encapsulate components correctly
24.2 Put models and page data in fields
24.3 Correct naming for Wicket IDs
24.4 Avoid changes at the component tree
24.5 Implement visibilities of components correctly
24.6 Always use models
24.7 Do not unwrap models within the constructor hierarchy
24.8 Pass models extended components
24.9 Validators must not change any data or models
24.10 Do not pass components to constructors
24.11 Use the Wicket session only for global data
24.12 Do not use factories for components
24.13 Every page and component must be tested
24.14 Avoid interactions with other servlet filters
24.15 Cut small classes and methods
24.16 The argument "Bad documentation"
24.17 Summary
25 Wicket Internals
25.1 Page storing
26 Working with Maven (Appendix)
26.1 Switching Wicket to DEPLOYMENT mode
26.2 Creating a Wicket project from scratch and importing it into our favourite IDE
27 Project WicketStuff (Appendix)
27.1 What is project WicketStuff
27.2 Module tinymce
27.3 Module wicketstuff-gmap3
27.4 Module wicketstuff-googlecharts
27.5 Module wicketstuff-inmethod-grid
27.6 Module wicketstuff-rest-annotations
27.7 Module stateless
28 Lost In Redirection With Apache Wicket (Appendix)
29 Contributing to this guide (Appendix)

5

1 Introduction
Wicket has been around since 2004 and it has been an Apache project since 2007. During these years it has
proved to be a solid and valuable solution for building enterprise web applications.
Wicket core developers have done a wonderful job with this framework and they continue to improve it release
after release. However Wicket never provided a freely available documentation and even if you can find on
Internet many live examples and many technical articles on it (most of them at Wicket Library and at Wicket in
Action ), the lack of an organized and freely available documentation has always been a sore point for this
framework.
That's quite an issue because many other popular frameworks (like Spring, Hibernate or Struts) offer a vast and
very good documentation which substantially contributed to their success.
This document is not intended to be a complete reference for Wicket but it simply aims to be a straightforward
introduction to the framework that should significantly reduce its learning curve. What you will find here reflects
my experience with Wicket and it's strictly focused on the framework. The various Wicket-related topics are
gradually introduced using pragmatic examples of code that you can find in the according repository on Github.
However remember that Wicket is a vast and powerful tool, so you should feel confident with the topics exposed
in this document before starting to code your real applications!
For those who need further documentation on Wicket, there are many good books available for this framework.
Hope you'll find this guide helpful. Have fun with Wicket!
Andrea Del Bene, adelbene@apache.org
PS: this guide is based on Wicket 6. However if you are using an older version you should find this guide useful
as well, but it's likely that the code and the snippets won't work with your version.
PPS: although I've tried to do my best working on this tutorial, this document is a work in progress and may
contain errors and/or omissions. That's why any feedback of any kind is REALLY appreciated!

Project started by

6

2 How to use the example code
Most of the code you will find in this document is available as a Git repository and is licensed under the ASF 2.0.
To get a local copy of the repository you can run the clone command from shell:
git clone https://github.com/bitstorm/Wicket-tutorial-examples.git

If you are using Wicket 6.x remember to switch to branch wicket-6.x

If you aren't used to Git, you can simply download the whole source as a zip archive:

The repository contains a multi-module Maven project. Every subproject is contained in the relative folder of the
repository:

When the example code is used in the document, you will find the name of the subproject it belongs to. If you
don't have any experience with Maven, you can read Appendix A where you can learn the basic commands
needed to work with the example projects and to import them into your favourite IDE (NetBeans, IDEA or
Eclipse).

7

3 Why should I learn Wicket?
Software development is a challenging activity and developers must keep their skills up-to-date with new
technologies.
But before starting to learn the last “coolest” framework we should always ask ourself if it is the right tool for us
and how it can improve our everyday job. Java's ecosystem is already full of many well-known web frameworks,
so why should we spend our time learning Wicket?
This chapter will show you how Wicket is different from other web frameworks you may know and it will explain
also how it can improve your life as web developer.

3.1 We all like spaghetti :-) ...
...but we all hate spaghetti code! That's why in the first half of the 2000s we have seen the birth of so many web
frameworks. Their mission was to separate our business code from presentation layer (like JSP pages).
Some of theme (like Struts, Spring MVC, Velocity, etc...) have become widely adopted and they made the MVC
pattern very popular among developers. However, none of these frameworks offers a real object-oriented (OO)
abstraction for web pages and we still have to take care of web-related tasks such as HTTP request/response
handling, URLs mapping, storing data into user session and so on.
The biggest limit of MVC frameworks is that they don't do much to overcome the impedance mismatch between
the stateless nature of HTTP protocol and the need of our web applications of handling a (very complex) state.
To overcome these limits developers have started to adopt a new generation of component oriented web
frameworks designed to provide a completely different approach to web development.

3.2 Component oriented frameworks - an overview
Component oriented frameworks differ from classic web frameworks in that they build a model of requested page
on the server side and the HTML sent back to the client is generated according to this model. You can think of
the model as if it was an “inverse” JavaScript DOM, meaning that:
1. is built on server-side
2. is built before HTML is sent to client
3. HTML code is generated using this model and not vice versa.

General schema of page request handling for a component oriented framework
With this kind of framework our web pages and their HTML components (forms, input controls, links, etc...), are
pure class instances. Since pages are class instances they live inside the JVM heap and we can handle them as
we do with any other Java class. This approach is very similar to what GUI frameworks (like Swing or SWT) do
with desktop windows and their components. Wicket and the other component oriented frameworks bring to web
development the same kind of abstraction that GUI frameworks offer when we build a desktop application. Most
of those kind of frameworks hide the details of the HTTP protocol and naturally solve the problem of its stateless
nature.

3.3 Benefits of component oriented frameworks for web development
8

At this point some people may still wonder why OOP is so important also for web development and what benefits
it can bring to developers. Let's quickly review the main advantages that this paradigm can offer us:
Web pages are objects: web pages are not just text files sent back to the client. They are object instances
and we can harness OOP to design web pages and their components. With Wicket we can also apply
inheritance to HTML markup in order to build a consistent graphic layout for our applications (we will see
markup inheritance in chapter 4.2).
We don't have to worry about application's state: pages and components can be considered stateful
entities. They are Java objects and they can keep a state inside them and reference other objects. We can
stop worrying about keeping track of user data stored inside the HttpSession and we can start managing
them in a natural and transparent way.
Testing web applications is much easier: since pages and components are pure objects, you can use
JUnit to test their behavior and to ensure that they render as expected. Wicket has a set of utility classes for
unit testing that simulate user interaction with web pages, hence we can write acceptance tests using just
JUnit without any other test framework (unit testing is covered in chapter 21).

3.4 Wicket vs the other component oriented frameworks
Wicket is not the only component oriented framework available in the Java ecosystem. Among its competitors we
can find GWT (from Google), JSF (from Oracle), Vaadin (from Vaadin Ltd.), etc… Even if Wicket and all those
other frameworks have their pros and cons, there are good reasons to prefer Wicket over them:
Wicket is 100% open source: Wicket is a top Apache project and it doesn't depend on any private
company. You don't have to worry about future licensing changes, Wicket will always be released under
Apache license 2.0 and freely available.
Wicket is a community driven project: The Wicket team supports and promotes the dialogue with the
framework's users through two mailing lists (one for users and another one for framework developers) and
an Apache JIRA (the issue tracking system). Moreover, as any other Apache project, Wicket is developed
paying great attention to user feedbacks and to suggested features.
Wicket is just about Java and good old HTML: almost all web frameworks force users to adopt special
tags or to use server side code inside HTML markup. This is clearly in contrast with the concept of
separation between presentation and business logic and it leads to a more confusing code in our pages. In
Wicket we don't have to take care of generating HTML inside the page itself, and we won't need to use any
tag other than standard HTML tags. All we have to do is to attach our components (Java instances) to the
HTML tags using a simple tag attribute called wicket:id (we will shortly see how to use it).
With Wicket we can easily use JavaBeans and POJO in our web tier: one of the most annoying and
error-prone task in web development is collecting user input through a form and keeping form fields
updated with previously inserted values. This usually requires a huge amount of code to extract input from
request parameters (which are strings), parse them to Java types and store them into some kind of
variable. And this is just half of the work we have to do as we must implement the inverse path (load data
from Java to the web form).Moreover, most of the times our forms will use a JavaBean or a POJO as
backing object, meaning that we must manually map form fields with the corresponding object fields and
vice versa. Wicket comes with an intuitive and flexible mechanism that does this mapping for us without any
configuration overhead (using a convention over configuration approach) and in a transparent way. Chapter
10 will introduce the concept of Wicket model and we will learn how to harness this entity with forms.
No complex XML needed: Wicket was designed to minimize the amount of configuration files needed to
run our applications. No XML file is required except for the standard deployment descriptor web.xml (unless
you are using Servlet 3 or a later version. See Chapter 4 for more details).

9

4 Wicket says “Hello world!”
Wicket allows us to design our web pages in terms of components and containers, just like AWT does with
desktop windows. Both frameworks share the same component-based architecture: in AWT we have a Windows
instance which represents the physical windows containing GUI components (like text fields, radio buttons,
drawing areas, etc...), in Wicket we have a WebPage instance which represents the physical web page
containing HTML components (pictures, buttons, forms, etc… ) .

In both frameworks we find a base class for GUI components called Component. Wicket pages can be
composed (and usually are) by many components, just like AWT windows are composed by Swing/AWT
components. Both frameworks promote the reuse of presentation code and GUI elements building custom
components. Even if Wicket already comes with a rich set of ready-to-use components, building custom
components is a common practice when working with this framework. We'll learn more about custom
components in the next chapters.

4.1 Wicket distribution and modules
Wicket is available as a binary package on the main site http://wicket.apache.org . Inside this archive we can find
the distribution jars of the framework. Each jar corresponds to a sub-module of the framework. The following
table reports these modules along with a short description of their purpose and with the related dependencies:
Module'sname

Description

Dependencies

wicket-core

Contains the main classes of the framework, like class
Component and Application.

wicket-request,
wicket-util

wicket-request

This module contains the classes involved into web request
wicket-util
processing.

wicket-util

Contains general-purpose utility classes for functional areas such
None
as I/O, lang, string manipulation, security, etc...

wicket-datetime

Contains special purpose components designed to work with
wicket-core
date and time.

wicket-bean-validation

Provides support for JSR 303 standard validation.

wicket-devutils

Contains utility classes and components to help developers with wicket-core,
tasks such as debugging, class inspection and so on.
wicket-extensions

wicket-extensions

Contains a vast set of built-in components to build a rich UI for
wicket-core
our web application (Ajax support is part of this module).

wicket-auth-roles

Provides support for role-based authorization.

wicket-core

wicket-core

This module provides common classes to support Inversion Of

10

wicket-ioc

Control. It's used by both Spring and Guice integration module.

wicket-core

wicket-guice

This module provides integration with the dependency injection wicket-core,
framework developed by Google.
wicket-ioc

wicket-spring

This module provides integration with Spring framework.

wicket-velocity

This module provides panels and utility class to integrate Wicket
wicket-core
with Velocity template engine.

wicket-jmx

This module provides panels and utility class to integrate Wicket
wicket-core
with Java Management Extensions.

wicket-objectsizeof-agent

Provides integration with Java agent libraries and instrumentation
wicket-core
tools.

wicket-core,
wicket-ioc

Please note that the core module depends on the utility and request modules, hence it cannot be used without
them.

4.2 Configuration of Wicket applications
In this chapter we will see a classic Hello World! example implemented using a Wicket page with a built-in
component called Label (the code is from project the HelloWorldExample). Since this is the first example of the
guide, before looking at Java code we will go through the common artifacts needed to build a Wicket application
from scratch.

All the example projects presented in this document have been generated using Maven
and the utility page at http://wicket.apache.org/start/quickstart.html . Appendix A contains
the instructions needed to use these projects and build a quickstart application using
Apache Maven. All the artifacts used in the next example (files web.xml, HomePage.class
and HomePage.html) are automatically generated by Maven.

Wicket application structure
A Wicket application is a standard Java EE web application, hence it is deployed through a web.xml file placed
inside folder WEB-INF:

Illustration : The standard directory structure of a Wicket application
The
content
of
web.xml
declares
a
servlet
filter
(class
org.apache.wicket.Protocol.http.WicketFilter) which dispatches web requests to our Wicket
application:


Wicket Test

TestApplication
org.apache.wicket.protocol.http.WicketFilter

applicationClassName
org.wicketTutorial.WicketApplication




11

TestApplication
/*



Since this is a standard servlet filter we must map it to a specific set of URLs through the 
tag). In the xml above we have mapped every URL to our Wicket filter.
If we are using Servlet 3 or a later version, we can of course use a class in place of web.xml to configure our
application. The following example uses annotation @WebFilter.
@WebFilter(value = "/*", initParams = { @WebInitParam(name = "applicationClassName", value =
"com.mycompany.WicketApplication"),
@WebInitParam(name= "filterMappingUrlPattern", value="/*") })
public class ProjectFilter extends WicketFilter {
}

Wicket can be started in two modes named respectively DEVELOPMENT and
DEPLOYMENT. The first mode activates some extra features which help application
development, like resources monitoring and reloading, full stack trace rendering of
exceptions, an AJAX debugger window, etc… The DEPLOYMENT mode turns off all
these features optimizing performances and resource consumption. In our example
projects we will use the default mode which is DEVELOPMENT. Chapter 24.1 contains
the chapter “Switching Wicket to DEPLOYMENT mode“ where we can find further details
about these two modes as well as the possible ways we have to set the desired one. In
any case, DO NOT deploy your applications in a production environment without switching
to DEPLOYMENT mode!

The application class
If we look back at web.xml we can see that we have provided the Wicket filter with a parameter called
applicationClassName. This value must be the fully qualified class name of a subclass of
org.apache.wicket.Application. This subclass represents our web application built upon Wicket and it's
responsible for configuring it when the server is starting up. Most of the times our custom application class won't
inherit
directly
from
class
Application ,
but
rather
from
class
org.apache.wicket.protocol.http.WebApplication which provides a closer integration with servlet
infrastructure. Class Application comes with a set of configuration methods that we can override to customize
our application's settings. One of these methods is getHomePage() that must be overridden as it is declared
abstract:
public abstract Class getHomePage()

As you may guess from its name, this method specifies which page to use as homepage for our application.
Another important method is init():
protected void init()

This method is called when our application is loaded by the web server (Tomcat, Jetty, etc...) and is the ideal
place to put our configuration code. The Application class exposes its settings grouping them into interfaces
(you can find them in package org.apache.wicket.settings). We can access these interfaces through
getter methods that will be gradually introduced in the next chapters when we will cover the related settings.
The current application's instance can be retrieved at any time calling static method Application.get() in
our code. We will give more details about this method in chapter 9.3. The content of the application class from
project HelloWorldExample is the following:

12

public class WicketApplication extends WebApplication
{
@Override
public Class getHomePage()
{
return HomePage.class;
}
@Override
public void init()
{
super.init();
// add your configuration here
}
}

Since this is a very basic example of a Wicket application, we don't need to specify anything inside the init
method. The home page of the application is the HomePage class. In the next paragraph we will see how this
page is implemented and which conventions we have to follow to create a page in Wicket.

Declaring a WicketFilter inside web.xml descriptor is not the only way we have to
kickstart our application. If we prefer to use a servlet instead of a filter, we can use class
org.apache.wicket.protocol.http.WicketServlet. See the JavaDoc for further
details.

4.3 The HomePage class
To complete our first Wicket application we must explore the home page class that is returned by the
Application's method getHomePage() seen above. In Wicket a web page is a subclass of
org.apache.wicket.WebPage. This subclass must have a corresponding HTML file which will be used by the
framework as template to generate its HTML markup. This file is a regular plain HTML file (its extension must be
html).
By default this HTML file must have the same name of the related page class and must be in the same package:

Illustration :Page class and its related HTML file
If you don't like to put class and html side by side (let's say you want all your HTML files in a separated folder)
you can use Wicket settings to specify where HTML files can be found. We will cover this topic later in chapter
15.9.
The Java code for the HomePage class is the following:
package org.wicketTutorial;
import org.apache.wicket.request.mapper.parameter.PageParameters;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.WebPage;
public class HomePage extends WebPage {
public HomePage() {
add(new Label("helloMessage", "Hello WicketWorld!"));
}
}

Apart from subclassing WebPage, HomePage defines a constructor that adds a Label component to itself.
Method
add(Component
component)
is
inherited
from
ancestor
class
org.apache.wicket.MarkupContainer and is used to add children components to a web page. We'll see
more
about
MarkupContainer
later
in
chapter
5.2.
Class
org.apache.wicket.markup.html.basic.Label is the simplest component shipped with Wicket. It just
inserts a string (the second argument of its constructor) inside the corresponding HTML tag. Just like any other
Wicket component, Label needs a textual id ('helloMessage' in our example) to be instantiated. At runtime

13

Wicket will use this value to find the HTML tag we want to bind to the component. This tag must have a special
attribute called wicket:id and its value must be identical to the component id (comparison is case-sensitive!).
Here is the HTML markup for HomePage (file HomePage.html):




Apache Wicket HelloWorld


[Label's message goes here]
We can see that the wicket:id attribute is set according to the value of the component id. If we run this example we will see the text Hello WicketWorld! Inside a
tag. Label replaces the original content of its tag (in our example Label's message goes here) with the string passed as value (Hello WicketWorld! in our example). If we specify a wicket:id attribute for a tag without adding the corresponding component in our Java code, Wicket will throw a ComponentNotFound Exception. On the contrary if we add a component in our Java code without specifying a corresponding wicket:id attribute in our markup, Wicket will throw a WicketRuntimeException. 4.4 Wicket Links The basic form of interaction offered by web applications is to navigate through pages using links. In HTML a link is basically a pointer to another resource that most of the time is another page. Wicket implements links with component org.apache.wicket.markup.html.link.Link, but due to the component-oriented nature of the framework, this component is quite different from classic HTML links. Following the analogy with GUI frameworks, we can consider Wicket link as a “click” event handler: its purpose is to perform some actions (on server side!) when the user clicks on it. That said, you shouldn't be surprised to find an abstract method called onClick() inside the Link class. In the following example we have a page with a Link containing an empty implementation of onClick: public class HomePage extends WebPage { public HomePage(){ add(new Link("id"){ @Override public void onClick() { //link code goes here } }); } } By default after onClick has been executed, Wicket will send back to the current page to the client web browser. If we want to navigate to another page we must use method setResponsePage of class Component: public class HomePage extends WebPage { public HomePage(){ add(new Link("id"){ @Override public void onClick() { //we redirect browser to another page. setResponsePage(AnotherPage.class); } 14 }); } } In the example above we used a version of setResponsePage which takes as input the class of the target page. In this way a new instance of AnotherPage will be created each time we click on the link. The other version of setResponsePage takes in input a page instance instead of a page class: @Override public void onClick() { //we redirect browser to another page. AnotherPage anotherPage = new AnotherPage(); setResponsePage(anotherPage); } The difference between using the first version of setResponsePage rather than the second one will be illustrated in chapter 8, when we will introduce the topic of stateful and stateless pages. For now, we can consider them as equivalent. Wicket comes with a rich set of link components suited for every need (links to static URL, Ajax-enhanced links, links to a file to download, links to external pages and so on). We will see them in chapter 10. We can specify the content of a link (i.e. the text of the picture inside it) with its method setBody. This method takes in input a generic Wicket model, which will be the topic of chapter 11. 4.5 Summary In this chapter we have seen the basic elements that compose a Wicket application. We have started preparing the configuration artifacts needed for our applications. As promised in chapter 2.4, we needed to put in place just a minimal amount of XML with an application class and a home page. Then we have continued our “first contact” with Wicket learning how to build a simple page with a label component as child. This example page has shown us how Wicket maps components to HTML tags and how it uses both of them to generate the final HTML markup. In the last paragraph we had a first taste of Wicket links and we have seen how they can be considered as a “click” event listener and how they can be used to navigate from a page to another. 15 5 Wicket as page layout manager Before going ahead with more advanced topics, we will see how to maintain a consistent layout across our site using Wicket and its component-oriented features. Probably this is not the most interesting use we can get out of Wicket, but it is surely the simplest one so it's the best way to get our hands dirty with some code. 5.1 Header, footer, left menu, content, etc... There was a time in the 90s when Internet was just a buzzword and watching a plain HTML page being rendered by a browser was a new and amazing experience. In those days we used to organize our page layout using the HTML tag. Over the years this tag has almost disappeared from our code and it survives only in few specific domains. For example is still being used by JavaDoc. With the adoption of server side technologies like JSP, ASP or PHP the tag has been replaced by a template-based approach where we divide our page layout into some common areas that will be present in each page of our web application. Then, we manually insert these areas in every page including the appropriate markup fragments. In this chapter we will see how to use Wicket to build a site layout. The sample layout we will use is a typical page layout consisting of the following areas: a header which could contain site title, some logos, a navigation bar, etc... a left menu with a bunch of links to different areas/functionalities of the site. a footer with generic informations like web master's email, the company address, etc... a content area which usually contains the functional part of the page. The following picture summarises the layout structure: Once we have chosen a page layout, our web designer can start building up the site theme. The result is a beautiful mock of our future web pages. Over this mock we can map the original layout areas: 16 Now in order to have a consistent layout across all the site, we must ensure that each page will include the layout areas seen above. With an old template-based approach we must manually put them inside every page. If we were using JSP we would probably end up using include directive to add layout areas in our pages. We would have one include for each of the areas (except for the content): For the sake of simplicity we can consider each included area as a static HTML fragment. Now let's see how we can handle the layout of our web application using Wicket. 17 5.2 Here comes the inheritance! The need of ensuring a consistent layout across our pages unveiled a serious limit of the HTML: the inability to apply inheritance to web pages and their markup. Wouldn't be great if we could write our layout once in a page and then inherit it in the other pages of our application? One of the goals of Wicket is to overcome this kind of limit. Markup inheritance As we have seen in the previous chapter, Wicket pages are pure Java classes, so we can easily write a page which is a subclass of another parent page. But in Wicket inheritance is not limited to the classic object-oriented code inheritance. When a class subclasses a WebPage it also inherits the HTML file of the parent class. This type of inheritance is called markup inheritance. To better illustrate this concept let's consider the following example where we have a page class called GenericSitePage with the corresponding HTML file GenericSitePage.html. Now let's create a specific page called OrderCheckOutPage where users can check out their orders on our web site. This class extends GenericSitePage but we don't provide it with any corresponding HTML file. In this scenario OrderCheckOutPage will use GenericSitePage.html as markup file: Markup inheritance comes in handy for page layout management as it helps us avoid the burden of checking that each page conforms to the site layout. However to fully take advantage of markup inheritance we must first learn how to use another important component of the framework that supports this feature: the panel. If no markup is found (nor directly assigned to the class, neither inherited from an ancestor) a MarkupNotFoundException is thrown. Panel class Class org.apache.wicket.markup.html.panel.Panel is a special component which lets us reuse GUI code and HTML markup across different pages and different web applications. It shares a common ancestor class with WebPage class, which is org.apache.wicket.MarkupContainer: 18 Illustration: Hierarchy of WebPage and Panel classes Subclasses of MarkupContainer can contain children components that can be added with method add(Component...) (seen in chapter 3.3). MarkupContainer implements a full set of methods to manage children components. The basic operations we can do on them are: add one or more children components (with method add). remove a specific child component (with method remove). retrieve a specific child component with method get(String). The string parameter is the id of the component or its relative path if the component is nested inside other MarkupContainers. This path is a colon-separated string containing also the ids of the intermediate containers traversed to get to the child component. To illustrate an example of component path, let's consider the code of the following page: MyPanel myPanel = new MyPanel ("innerContainer"); add(myPanel); Component MyPanel is a custom panel containing only a label having "name" as id. Under those conditions we could retrieve this label from the container page using the following path expression: Label name = (Label)get("innerContainer:name"); replace a specific child component with a new component having the same id (with method replace). iterate thought children components with the iterator returned by method iterator or using visitor pattern1 with methods visitChildren. Both Panel and WebPage have their own associated markup file which is used to render the corresponding component. If such file is not provided, Wicket will apply markup inheritance looking for a markup file through 19 their ancestor classes. When a panel is attached to a container, the content of its markup file is inserted into its related tag. While panels and pages have much in common, there are some notable differences between these two components that we should keep in mind. The main difference between them is that pages can be rendered as standalone entities while panels must be placed inside a page to be rendered. Another important difference is the content of their markup file: for both WebPage and Panel this is a standard HTML file, but Panel uses a special tag to indicate which part of the whole file will be considered as markup source. This tag is . A markup file for a panel will typically look like this: The HTML outside tag will be removed during rendering phase. The space outside this tag can be used by both web developers and web designers to place some mock HTML to show how the final panel should look like. 5.3 Divide et impera! Let's go back to our layout example. In chapter 5.1 we have divided our layout in common areas that must be part of every page. Now we will build a reusable template page for our web application combining pages and panels. The code examples are from project MarkupInheritanceExample. Panels and layout areas First, let's build a custom panel for each layout area (except for 'content' area). For example given the header area we can build a panel called HeaderPanel with a related markup file called HeaderPanel.html containing the HTML for this area:
Jug4Tenda

Gestione Anagrafica

The class for this panel simply extends base class Panel: 20 package helloWorld.layoutTenda; import org.apache.wicket.markup.html.panel.Panel; public class HeaderPanel extends Panel { public HeaderPanel(String id) { super(id); } } For each layout area we will build a panel like the one above that holds the appropriate HTML markup. In the end we will have the following set of panels: HeaderPanel FooterPanel MenuPanel Content area will change from page to page, so we don't need a reusable panel for it. Template page Now we can build a generic template page using our brand new panels. Its markup is quite straightforward : … …
content
The HTML code for this page implements the generic left-menu layout of our site. You can note the 4
tags used as containers for the corresponding areas. The page class contains the code to physically assemble the page and panels: package helloWorld.layoutTenda; import org.apache.wicket.markup.html.WebPage; import org.apache.wicket.Component; import org.apache.wicket.markup.html.basic.Label; public class JugTemplate extends WebPage { public static final String CONTENT_ID = "contentComponent"; private Component headerPanel; private Component menuPanel; private Component footerPanel; public JugTemplate(){ add(headerPanel = new HeaderPanel("headerPanel")); add(menuPanel = new MenuPanel("menuPanel")); add(footerPanel = new FooterPanel("footerPanel")); add(new Label(CONTENT_ID, "Put your content here")); } //getters for layout areas //… } Done! Our template page is ready to be used. Now all the pages of our site will be subclasses of this parent page and they will inherit the layout and the HTML markup. They will only substitute the Label inserted as content 21 area with their custom content. Final example As final example we will build the login page for our site. We will call it SimpleLoginPage. First, we need a panel containing the login form. This will be the content area of our page. We will call it LoginPanel and the markup is the following:
Login Username:
Password:

The class for this panel just extends Panel class so we won't see the relative code. The form of this panel is for illustrative purpose only. We will see how to work with Wicket forms in chapters 11 and 12. Since this is a login page we don't want it to display the left menu area. That's not a big deal as Component class exposes a method called setVisible which sets whether the component and its children should be displayed. The resulting Java code for the login page is the following: package helloWorld.layoutTenda; import helloWorld.LoginPanel; import org.apache.wicket.event.Broadcast; import org.apache.wicket.event.IEventSink; public class SimpleLoginPage extends JugTemplate { public SimpleLoginPage(){ super(); replace(new LoginPanel(CONTENT_ID)); getMenuPanel().setVisible( false); } } Obviously this page doesn't come with a related markup file. You can see the final page in the following picture: 22 5.4 Markup inheritance with the wicket:extend tag With Wicket we can apply markup inheritance using another approach based on the tag . This tag is used inside the parent's markup to define where the children pages/panels can “inject” their custom markup extending the markup inherited from the parent component. An example of a parent page using the tag is the following: This is parent body! The markup of a child page/panel must be placed inside the tag . Only the markup inside will be included in final markup. Here is an example of child page markup: This is child body! Considering the two pages seen above, the final markup generated for child page will be the following: This is parent body! This is child body! Our example revisited Applying tag to our layout example, we obtain the following markup for the main template page:
23 We have replaced the
tag of the content area with the tag . Going forward with our example we can build a login page creating class SimpleLoginPage which extends the JugTemplate page, but with a related markup file like this:
Login Username:
Password:

As we can see this approach doesn't require to create custom panels to use as content area and it can be useful if we don't have to handle a GUI with a high degree of complexity. 5.5 Summary Wicket applies inheritance also to HTML markup making layout management much easier and less error-prone. Defining a master template page to use as base class for the other pages is a great way to build a consistent layout and use it across all the pages on the web site. During the chapter we have also introduced the Panel component, a very important Wicket class that is primarily designed to let us divide our pages in smaller and reusable UI components. 24 6 Keeping control over HTML Many Wicket newbies are initially scared by its approach to web development because they have the impression that the component-oriented nature of the framework prevents them from having direct control over the generated markup. This is due to the fact that many developers come from other server-side technologies like JSP where we physically implement the logic that controls how the final HTML is generated. This chapter will prevent you from having any initial misleading feeling about Wicket showing you how to control and manipulate the generated HTML with the built-in tools shipped with the framework. 6.1 Hiding or disabling a component At the end of the previous chapter we have seen how to hide a component calling its method setVisible. In a similar fashion, we can also decide to disable a component using method setEnabled. When a component is disabled all the links inside it will be in turn disabled (they will be rendered as ) and it can not fire JavaScript events. Class Component provides two getter methods to determinate if a component is visible or enabled: isVisible and isEnabled. Even if nothing prevents us from overriding these two methods to implement a custom logic to determinate the state of a component, we should keep in mind that methods isVisible and isEnabled are called multiple times before a component is fully rendered. Hence, if we place non-trivial code inside these two methods, we can sensibly deteriorate the responsiveness of our pages. As we will see in the next chapter, class Component provides method onConfigure which is more suited to contain code that contributes to determinate component states because it is called just once during rendering phase. 6.2 Modifing tag attributes To modify tag attributes we can use class org.apache.wicket.AttributeModifier. This class extends org.apache.wicket.behavior.Behavior and can be added to any component via the Component's add method. Class Behavior is used to expand component functionalities and it can also modify component markup. We will see this class in detail later in chapter 17.1. As first example of attribute manipulation let's consider a Label component bound to the following markup: Suppose we want to add some style to label content making it red and bolded. We can add to the label an AttributeModifier which creates the tag attribute style with value "color:red;font-weight:bold": label.add(new AttributeModifier("style", "color:red;font-weight:bold")); If attribute style already exists in the original markup, it will be replaced with the value specified by AttributeModifier. If we don't want to overwrite the existing value of an attribute we can use subclass AttributeAppender which will append its value to the existing one: label.add(new AttributeAppender("style", "color:red;font-weight:bold")); We can also create attribute modifiers using factory methods provided by class AttributeModifier and it's 25 also possible to prepend a given value to an existing attribute: //replaces existing value with the given one label.add(AttributeModifier.replace("style", "color:red;font-weight:bold")); //appends the given value to the existing one label.add(AttributeModifier.append("style", "color:red;font-weight:bold")); //prepends the given value to the existing one label.add(AttributeModifier.prepend("style", "color:red;font-weight:bold")); 6.3 Generating tag attribute 'id' Tag attribute id plays a crucial role in web development as it allows JavaScript to identify a DOM element. That's why class Component provides two dedicated methods to set this attribute. With method setOutputMarkupId(boolean output) we can decide if the id attribute will be rendered or not in the final markup (by default is not rendered). The value of this attribute will be automatically generated by Wicket and it will be unique for the entire page. If we need to specify this value by hand, we can use method setMarkupId(String id). The value of the id can be retrieved with method getMarkupId(). 6.4 Creating in-line panels with WebMarkupContainer Create custom panels is a great way to handle complex user interfaces. However, sometimes we may need to create a panel which is used only by a specific page and only for a specific task. In situations like these component org.apache.wicket.markup.html.WebMarkupContainer is better suited than custom panels because it can be directly attached to a tag in the parent markup without needing a corresponding html file (hence it is less reusable). Let's consider for example the main page of a mail service where users can see a list of received mails. Suppose that this page shows a notification box where user can see if new messages have arrived. This box must be hidden if there are no messages to display and it would be nice if we could handle it as if it was a Wicket component. Suppose also that this information box is a
tag like this inside the page:
//here's the body You've got new messages.
Under those conditions we can consider using a WebMarkupContainer component rather than implementing a new panel. The code needed to handle the information box inside the page could be the following: //Page initialization code WebMarkupContainer informationBox = new WebMarkupContainer ("informationBox"); informationBox.add(new Label("messagesNumber", messagesNumber)); add(informationBox); //If there are no new messages, hide informationBox informationBox.setVisible(false); As you can see in the snippet above we can handle our information box from Java code as we do with any other Wicket component. 6.5 Working with markup fragments Another circumstance in which we may prefer to avoid the creation of custom panels is when we want to conditionally display in a page small fragments of markup. In this case if we decided to use panels, we would end up having a huge number of small panel classes with their related markup file. To better cope with situations like this, Wicket defines component Fragment in package org.apache.wicket.markup.html.panel. Just like its parent component WebMarkupContainer, Fragment doesn't have its own markup file but it uses a markup fragment defined in the markup file of its parent 26 container, which can be a page or a panel. The fragment must be delimited with tag and must be identified by a wicket:id attribute. In addition to the component id, Fragment's constructor takes as input also the id of the fragment and a reference to its container. In the following example we have defined a fragment in a page and we used it as content area: Page markup: … …
Java code: Fragment fragment = new add(fragment); Fragment ("contentArea", "fragmentId", this); Fragments can be very helpful with complex pages or components. For example let's say that we have a page where users can register to our forum. This page should first display a form where user must insert his/her personal data (name, username, password, email and so on), then, once the user has submitted the form, the page should display a message like “Your registration is complete! Please check your mail to activate your user profile.”. Instead of displaying this message with a new component or in a new page, we can define two fragments: one for the initial form and one to display the confirmation message. The second fragment will replace the first one after the form has been submitted: Page markup:
Java code: Fragment fragment = new add(fragment); Fragment ("contentArea", "formFrag", this); //form has been submitted Fragment fragment = new Fragment ("contentArea", "messageFrag", this); replace(fragment); 6.6 Adding header contents to the final page Panel's markup can also contain HTML tags which must go inside header section of the final page, like tags Wicket will take care of placing the content of inside the tag of the final page. The tag can also be used with children pages/panels which extend parent markup using tag . The content of the tag is added to the header section once per component class. In other words, if we add multiple instances of the same panel to a page, the tag will be populated just once with the content of . The tag is ideal if we want to define small in-line blocks of CSS or JavaScript. However Wicket provides also a more sophisticated technique to let components contribute to header section with in-line blocks and resource files like CSS or JavaScript files. We will see this technique later in chapter 15. 6.7 Using stub markup in our pages/panels Wicket's tag can be very useful when our web designer needs to show us how a page or a panel should look like. The markup inside this tag will be stripped out in the final page, so it's the ideal place for web designers to put their stub markup: 6.8 How to render component body only When we bind a component to its corresponding tag we can choose to get rid of this outer tag in the final markup. If we call method setRenderBodyOnly(true) on a component Wicket will remove the surrounding tag. For example given the following markup and code: HTML markup: Hello world page 28
[helloWorld]
Java code: Label label = new Label("helloWorld", “Hello World!”); label.setRenderBodyOnly(true); add(label); the output will be: Hello world page Hello World! As you can see the
tag used for component Label is not present in the final markup. 6.9 Hiding decorating elements with the wicket:enclosure tag Our data are rarely displayed alone without a caption or other graphic elements that make clear the meaning of their value. For example: Wicket comes with a nice utility tag called that automatically hides those decorating elements if the related data value is not visible. All we have to do is to put the involved markup inside this tag. Applying to the previous example we get the following markup: Now if component totalAmount is not visible, its description (Total amount:) will be automatically hidden. If we have more than a Wicket component inside we can use child attribute to specify which component will control the overall visibility:
child attribute supports also nested components with a colon-separated path:
6.10 Surrounding existing markup with Border 29 Component org.apache.wicket.markup.html.border.Border is a special purpose container created to enclose its tag body with its related markup. Just like panels and pages, borders also have their own markup file which is defined following the same rules seen for panels and pages. In this file tag is used to indicate which part of the content is to be considered as border markup:
foo

buz
The tag used in the example above is used to indicate where the body of the tag will be placed inside border markup. Now if we attached this border to the following tag bar we would obtain the following resulting HTML:
foo
bar
buz
Border can also contain children components which can be placed either inside its markup file or inside its corresponding HTML tag. In the first case children must be added to the border component with method addToBorder(Component...), while in the second case we must use the add(Component...) method. The following example illustrates both use cases: Border class: public class MyBorder extends Border { public MyBorder(String id) { super(id); } } Border Markup:

30 Border tag:
Initialization code for border: MyBorder myBorder = new MyBorder("myBorder"); myBorder.addToBorder(new Label("childMarkup", "Child inside markup.")); myBorder.add(new Label("childTag", "Child inside tag.")); add(myBorder); 6.11 Summary In this chapter we have seen the tools provided by Wicket to gain complete control over the generated HTML. However we didn't see yet how we can repeat a portion of HTML with Wicket. With classic server-side technologies like PHP or JSP we use loops (like while or for) inside our pages to achieve this result. To perform this task Wicket provides a special-purpose family of components called repeaters and designed to repeat their markup body to display a set of items. But to fully understand how these components work, we must first learn more of Wicket's basics. That's why repeaters will be introduced later in chapter 13. 31 7 Components lifecycle Just like applets and servlets, also Wicket components follow a lifecycle during their existence. In this chapter we will analyze each stage of this cycle and we will learn how to make the most of the hook methods that are triggered when a component moves from one stage to another. 7.1 Lifecycle stages of a component During its life a Wicket component goes through three basic stages: 1. Initialization: a component is instantiated by Wicket and prepared for the rendering phase. 2. Rendering: in this stage Wicket generates component markup. If a component contains children (i.e. is a subclass of MarkupContainer) it must first wait for them to be rendered before starting its own rendering. 3. Removing: this stage is triggered when a component is explicitly removed from its component hierarchy, i.e. when its parent invokes remove(component) on it. This stage is facultative and is never triggered for pages. The following picture shows the state diagram of component lifecycle: Once a component has been removed it can be added again to a container, but the initialization stage won't be executed again. If you read the JavaDoc of class Component you will find a more detailed description of component lifecycle. However this description introduces some advanced topics we didn't covered yet hence, to avoid confusion, in this chapter some details have been omitted and they will be covered later in the next chapters. For now you can consider just the simplified version of the lifecycle described above. 7.2 Hook methods for component lifecycle Class Component comes with a number of hook methods that can be overridden in order to customize component behavior during its lifecycle. In the following table these methods are grouped according to the stage in which they are invoked (and they are sorted by execution order): Cycle stage Involved methods Initialization onInitialize Rendering onConfigure, onBeforeRender, onRender, onAfterRenderChildren, onAfterRender Removing onRemove onComponentTag, onComponentTagBody, 32 Now let's take a closer look at each stage and to at hook methods. 7.3 Initialization stage This stage is performed at the beginning of the component lifecycle. During initialization, the component has already been inserted into its component hierarchy so we can safely access to its parent container or to its page with methods getParent() or getPage(). The only method triggered during this stage is onInitialize(). This method is a sort of “special” constructor where we can execute a custom initialization of our component. Since onInitialize is similar to a regular constructor, when we override this method we have to call super.onInitialize inside its body, usually as first instruction. 7.4 Rendering stage This stage is triggered each time a component is rendered by Wicket, typically when its page is requested or when it is refreshed via AJAX. Method onConfigure Method onConfigure() has been introduced in order to provide a good point to manage the component states such as its visibility or enabled state. This method is called before the render phase starts. As stated in chapter 6.1, isVisible and isEnabled are called multiple times when a page or a component is rendered, so it's highly recommended not to directly override these method, but rather to use onConfigure to change component states. On the contrary method onBeforeRender (see the next paragraph) is not indicated for this task because it will not be invoked if component visibility is set to false. Method onBeforeRender The most important hook method of this stage is probably onBeforeRender(). This method is called before a component starts its rendering phase and it is our last chance to change its children hierarchy. If we want add/remove children components this is the right place to do it. In the next example (project LifeCycleStages) we will create a page which alternately displays two different labels, swapping between them each time it is rendered: public class HomePage extends WebPage { private Label firstLabel; private Label secondLabel; public HomePage(){ firstLabel = new Label("label", "First label"); secondLabel = new Label("label", "Second label"); add(firstLabel); add(new Link("reload"){ @Override public void onClick() { } }); } @Override protected void onBeforeRender() { if(contains(firstLabel, true)) replace(secondLabel); else replace(firstLabel); super.onBeforeRender(); } } The code inside onBeforeRender() is quite trivial as it just checks which label among firstLabel and secondLabel is currently inserted into the component hierarchy and it replaces the inserted label with the other one. This method is also responsible for invoking children onBeforeRender() so if we decide to override it we have to call super.onBeforeRender(). However, unlike onInitialize(), the call to superclass method should 33 be placed at the end of method's body in order to affect children's rendering with our custom code. Please note that in the example above we can trigger the rendering stage pressing F5 key or clicking on link “reload”. If we forget to call superclass version of methods onInitialize() or onBeforeRender(), Wicket will throw an IllegalStateException with the following message: java.lang.IllegalStateException: org.apache.wicket.Component has not been properly initialized. Something in the hierarchy of has not called super.onInitialize()/onBeforeRender() in the override of onInitialize()/ onBeforeRender() method Method onComponentTag Method onComponentTag(ComponentTag) is called to process component tag, which can be freely manipulated through its argument of type org.apache.wicket.markup.ComponentTag. For example we can add/remove tag attributes with methods put(String key, String value) and remove(String key), or we can even decide to change the tag or rename it with method setName(String) (the following code is taken from project OnComponentTagExample): Markup code:

Java code: public class HomePage extends WebPage { public HomePage() { add(new Label("helloMessage", "Hello World"){ @Override protected void onComponentTag(ComponentTag tag) { super.onComponentTag(tag); //Turn the h1 tag to a span tag.setName( "span"); //Add formatting style tag.put( "style", "font-weight:bold"); } }); } } Generated markup: Hello World Just like we do with onInitialize, if we decide to override onComponentTag we must remember to call the same method of the super class because also this class may also customize the tag. Overriding onComponentTag is perfectly fine if we have to customize the tag of a specific component, but if we wanted to reuse the code across different components we should consider to use a behavior in place of this hook method. 34 We have already seen in chapter 6.2 how to use behavior AttributeModifier to manipulate the tag's attribute. In chapter 17.1 we will see that base class Behavior offers also a callback method named onComponentTag(ComponentTag, Component) that can be used in place of the hook method onComponentTag(ComponentTag). Methods onComponentTagBody Method onComponentTagBody(MarkupStream, ComponentTag) is called to process the component tag's body. Just like onComponentTag it takes as input a ComponentTag parameter representing the component tag. In addition, we also find a MarkupStream parameter which represents the page markup stream that will be sent back to the client as response. onComponentTagBody can be used in combination with the Component 's method replaceComponentTagBody to render a custom body under specific conditions. For example (taken from project OnComponentTagExample) we can display a brief description instead of the body if the label component is disabled: public class HomePage extends WebPage { public HomePage() { add(new Label("helloMessage", "Hello World"){ @Override protected void onComponentTagBody(MarkupStream markupStream, ComponentTag tag) { if(!isEnabled()) replaceComponentTagBody(markupStream, tag, "(the component is disabled)"); else super.onComponentTagBody(markupStream, tag); } }); } } Note that the original version of onComponentTagBody is invoked only when we want to preserve the standard rendering mechanism for the tag's body (in our example this happens when the component is enabled). 7.5 Removing stage This stage is triggered when a component is removed from its container hierarchy. The only hook method for this phase is onRemove(). If our component still holds some resources needed during rendering phase, we can override this method to release them. Once a component has been removed we are free to add it again to the same container or to a different one. Starting from version 6.18.0 Wicket added a further hook method called onReAdd() which is triggered every time a previously removed component is re-added to a cointainer. Please note that while onInitialize is called only the very first time a component is added, onReAdd is called every time it is re-added after having been removed. 7.6 Summary In this chapter we have seen which stages compose the lifecycle of Wicket components and which hook methods they provide. Overriding these methods we can dynamically modify the component hierarchy and we can enrich the behavior of our custom components. 35 8 Page versioning and caching This chapter explains how Wicket manages page instances, underlining the difference between stateful and stateless pages. The chapter also introduces some advanced topics like Java Serialization and multi-level cache. However, to understand what you will read you are not required to be familiar with these concepts. 8.1 Stateful pages vs stateless Wicket pages can be divided into two categories: stateful and stateless pages. Stateful pages are those which rely on user session to store their internal state and to keep track of user interaction. On the contrary stateless pages are those which don't change their internal state during their lifecycle and they don't need to occupy space into user session. From Wicket's point of view the biggest difference between these two types of page is that stateful pages are versioned, meaning that they will be saved into user session every time their internal state has changed. Wicket automatically assigns a session to the user the first time a stateful page is requested. Page versions are stored into user session using Java Serialization mechanism. Stateless pages are never versioned and that's why they don't require a valid user session. If we want to know whether a page is stateless or not, we can call the isPageStateless() method of class Page. In order to build a stateless page we must comply with some rules to ensure that the page won't need to use user session. These rules are illustrated in paragraph 8.3 but before talking about stateless pages we must first understand how stateful pages are handled and why they are versioned. 8.2 Stateful pages Stateful pages are versioned in order to support browser's back button: when this button is pressed Wicket must respond by rendering the same page instance previously used. A new page version is created when a stateful page is requested for the first time or when an existing instance is modified (for example changing its component hierarchy). To identify each page version Wicket uses a session-relative identifier called page id. This is a unique number and it is increased every time a new page version is created. In the final example of the previous chapter (project LifeCycleStages), you may have noticed the number appended at the end of URL. This number is the page id we are talking about: In this chapter we will use a revised version of this example project where the component hierarchy is modified inside the Link's onClick()method. This is necessary because Wicket creates a new page version only if the page is modified before its method onBeforeRender() is invoked. The code of the new home page is the following: public class HomePage extends WebPage { private static final long serialVersionUID = 1L; private Label firstLabel; private Label secondLabel; 36 public HomePage(){ firstLabel = new Label("label", "First label"); secondLabel = new Label("label", "Second label"); add(firstLabel); add(new Link("reload"){ @Override public void onClick() { if(getPage().contains(firstLabel, true)) getPage().replace(secondLabel); else getPage().replace(firstLabel); } }); } } Now if we run the new example (project LifeCycleStagesRevisited) and we click on the “Reload” button, a new page version is created and the page id is increased by one: If we press the back button the page version previously rendered (and serialized) will be retrieved (i.e. deserialized) and it will be used again to respond to our request (and page id is decremented): For more details about page storing you can take a look at paragraph "Page storing" from chapter "Wicket Internals". The content of this paragraph is from wiki page https://cwiki.apache.org/confluence/display/WICKET/Page+Storage. As we have stated at the beginning of this chapter, page versions are stored using Java serialization, therefore every object referenced inside a page must be serializable. In paragraph 11.6 we will see how to overcome this limit and work with non-serializable objects in our components using detachable Wicket models. Using a specific page version with PageReference To retrieve a specific page version in our code we can use class org.apache.wicket.PageReference by providing its constructor with the corresponding page id: //load page version with page id = 3 PageReference pageReference = new PageReference(3); //load the related page instance Page page = pageReference.getPage(); To get the related page instance we must use the method getPage. 37 Turning off page versioning If for any reason we need to switch off versioning for a given page, we can call its method setVersioned(false). Pluggable serialization Starting from version 1.5 it is possible to choose which implementation of Java serialization will be used by Wicket to store page versions. Wicket serializes pages using an implementation of interface org.apache.wicket.serialize.ISerializer . The default implementation is org.apache.wicket.serialize.java.JavaSerializer and it uses the standard Java serialization mechanism based on classes ObjectOutputStream and ObjectInputStream. However on Internet we can find other interesting serialization libraries like Kryo or Fast which perform faster then the standard implementation. The serializer in use can be customized with the setSerializer(ISerializer) method defined by setting interface org.apache.wicket.settings.IFrameworkSettings. We can access this interface inside the method init of the class Application using the getFrameworkSettings() method : @Override public void init() { super.init(); getFrameworkSettings().setSerializer(yourSerializer); } A serializer based on Kryo library and another one based on Fast are provided by the WicketStuff project. You can find more information on this project, as well as the instructions to use its modules, in Appendix B. Page caching By default Wicket persists versions of pages into a session-relative file on disk, but it uses a two-levels cache to speed up this process. The first level of the cache uses a http session attribute called “wicket:persistentPageManagerData-” to store pages. The second level cache stores pages into application-scoped variables which are identified by a session id and a page id. The following picture is an overview of these two caching levels: The session-scoped cache is faster then the other memory levels but it contains only the pages used to serve the last request. Wicket allows us to set the maximum amount of memory allowed for the application-scoped cache and for the page store file. Both parameters can be configured via setting interface org.apache.wicket.settings.IStoreSettings. This interface provides the setMaxSizePerSession(Bytes bytes) method to set the size for page store file. The 38 Bytes parameter is the maximum size allowed for this file: @Override public void init() { super.init(); getStoreSettings().setMaxSizePerSession(Bytes.kilobytes(500)); } Class org.apache.wicket.util.lang.Bytes is an utility class provided by Wicket to express size in bytes (for further details refer to the JavaDoc). For the second level cache we can use the setInmemoryCacheSize(int inmemoryCacheSize) method. The integer parameter is the maximum number of page instances that will be saved into application-scoped cache: @Override public void init() { super.init(); getStoreSettings().setInmemoryCacheSize(50); } Page expiration Page instances are not kept in the user session forever. They can be discarded when the limit set with the setMaxSizePerSession method is reached or (more often) when user session expires. When we ask Wicket for a page id corresponding to a page instance removed from the session, we bump into a PageExpiredException and we get the following default error page: This error page can be customized with the setPageExpiredErrorPage org.apache.wicket.settings.IApplicationSettings interface: method of the @Override public void init() { super.init(); getApplicationSettings().setPageExpiredErrorPage( CustomExpiredErrorPage.class); } The page class provided as custom error page must have a public constructor with no argument or a constructor that takes as input a single PageParameters argument (the page must be bookmarkable as described in paragraph 10.1.1). 8.3 Stateless pages Wicket makes it very easy to build stateful pages, but sometimes we might want to use an “old school” stateless page that doesn't keep memory of its state in the user session. For example consider the public area of a site or a login page: in those cases a stateful page would be a waste of resources or even a security threat, as we will see in paragraph paragraph 12.10. In Wicket a page can be stateless only if it satisfies the following requirements: 1. 39 1. it has been instantiated by Wicket (i.e. we don't create it with operator new) using a constructor with no argument or a constructor that takes as input a single PageParameters argument (class PageParameters will be covered in chapter 10.1). 2. All its children components (and behaviors) are in turn stateless, which means that their method isStateless must return true. The first requirement implies that, rather than creating a page by hand, we should rely on Wicket's capability of resolving page instances, like we do when we use method setResponsePage(Class page). In order to comply with the second requirement it could be helpful to check if all children components of a page are stateless. To do this we can leverage method visitChildren and the visitor pattern to iterate over components and test if their method isStateless actually returns true: @Override protected void onInitialize() { super.onInitialize(); visitChildren(new IVisitor() { @Override public void component(Component component, IVisit arg1) { if(!component.isStateless()) System.out.println("Component " + component.getId() + " is not stateless"); } }); } Alternatively, we could use the StatelessComponent utility annotation along with the StatelessChecker class (they are both in package org.apache.wicket.devutils.stateless). StatelessChecker will throw an IllegalArgumentException if a component annotated with StatelessComponent doesn't respect the requirements for being stateless. To use StatelessComponent annotation we must first add the StatelessChecker to our application as a component render listener: @Override public void init() { super.init(); getComponentPostOnBeforeRenderListeners().add(new StatelessChecker()); } Most of the Wicket's built-in components are stateful, hence they can not be used with a stateless page. However some of them have also a stateless version which can be adopted when we need to keep a page stateless. In the rest of the guide we will point out when a built-in component comes also with a stateless version. A page can be also explicitly declared as stateless setting the appropriate flag to true with the setStatelessHint(true) method. This method will not prevent us from violating the requirements for a stateless page, but if we do so we will get the following warning log message: Page '' is not stateless because of component with path '' 8.4 Summary In this chapter we have seen how page instances are managed by Wicket. We have learnt that pages can be divided into two families: stateless and stateful pages. Knowing the difference between the two types of pages is important to build the right page for a given task. However, to complete the discussion about stateless pages we still have to deal with two topics we have just outlined in this chapter: class PageParameters and bookmarkable pages. The first part of chapter 10 will cover these missing topics. 40 9 Under the hood of the request processing Although Wicket was born to provide a reliable and comprehensive object oriented abstraction for web development, sometimes we might need to work directly with “raw” web entities such as user session, web request, query parameters, and so on. For example this is necessary if we want to store an arbitrary parameter in the user session. Wicket provides wrapper classes that allow us to easily access to web entities without the burden of using the low-level APIs of Java Servlet Specification. However it will always be possible to access standard classes (like HttpSession, HttpServletRequest, etc...) that lay under our Wicket application. This chapter will introduce these wrapper classes and it will explain how Wicket uses them to handle the web requests initiated by the user's browser. 9.1 Class Application and request processing Beside configuring and initializing our application, the Application class is responsible for creating the internal entities used by Wicket to process a request. These entities are instances of the following classes: RequestCycle, Request, Response and Session. The next paragraphs will illustrate each of these classes, explaining how they are involved into request processing. 9.2 Request and Response classes The Request and Response classes are located in package org.apache.wicket.request and they provide an abstraction of the concrete request and response used by our web application. Both classes are declared as abstract but if our application class inherits from WebApplication it will use their sub classes ServletWebRequest and ServletWebResponse, both of them located inside the package org.apache.wicket.protocol.http.servlet.ServletWebRequest and ServletWebResponse wrap respectively a HttpServletRequest and a HttpServletResponse object. If we need to access to these low-level objects we can call Request's method getContainerRequest() and Response's method getContainerResponse(). 9.3 The “director” of request processing - RequestCycle Class org.apache.wicket.request.cycle.RequestCycle is the entity in charge of serving a web request. Our application class creates a new RequestCycle on every request with its method createRequestCycle(request, response). Method createRequestCycle is declared as final, so we can't override it to return a custom subclass of RequestCycle . Instead, we must build a request cycle provider implementing interface org.apache.wicket.IRequestCycleProvider, and then we must tell our application class to use it via the setRequestCycleProvider method. The current running request cycle can be retrieved at any time by calling its static method RequestCycle.get(). Strictly speaking this method returns the request cycle associated with the current (or local) thread, which is the thread that is serving the current request. A similar get() method is also implemented in classes org.apache.wicket.Application (as we have seen in paragraph 4.2.2) and org.apache.wicket.Session in order to get the application and the session in use by the current thread. The implementation of the get method takes advantage of the standard class java.lang.ThreadLocal. See its JavaDoc for an introduction to local-thread variables. 41 Class org.apache.wicket.Component provides the getRequestCycle() method which is a convenience method that internally invokes RequestCycle.get(): public final RequestCycle getRequestCycle() { return RequestCycle.get(); } RequestCycle and request processing This paragraph will provide just the basic informations about what happens behind the scenes of request processing. When you work with Wicket it's unlikely to have a need for customizing this process, so we won't cover this topic in detail. In order to process a request, RequestCycle delegates the task to another entity which implements interface org.apache.wicket.request.IRequestHandler. There are different implementations of this interface, each suited for a particular type of requested resource (a page to render, an AJAX request, an URL to an external page, etc.). To resolve the right handler for a given HTTP request, the RequestCycle uses a set of objects implementing the org.apache.wicket.request.IRequestMapper interface. The mapping interface defines the getCompatibilityScore(Request request) method which returns a score indicating how compatible the request mapper is for the current request. RequestCycle will choose the mapper with the highest score and it will call its mapRequest(Request request) method to get the proper handler for the given request. Once RequestCycle has resolved a request handler, it invokes its method respond(IRequestCycle requestCycle) to start request processing. The following sequence diagram recaps how a request handler is resolved by the RequestCycle: Developers can create additional implementations of IRequestMapper and add them to their application via the mount(IRequestMapper mapper) method of the WebApplication class. In paragraph 10.6 we will see how Wicket uses this method to add built-in mappers for mounted pages. Generating URL with the urlFor and mapUrlFor methods The RequestCycle is also responsible for generating the URL value (as CharSequence) for the following entities: a page class, via the urlFor(Class pageClass, PageParameters parameters) method 42 an IRequestHandler via the urlFor(IRequestHandler handler) method a ResourceReference via the urlFor(ResourceReference params) method (resource entities will be introduced in chapter 15). reference, PageParameters The overloaded urlFor method from above also has a corresponding version that returns an instance of org.apache.wicket.request.Url instead of a CharSequence. This version has the prefix 'map' in its name (i.e. it has mapUrlFor as full name). Method setResponsePage The RequestCycle class contains the implementation of the setResponsePage method we use to redirect a user to a specific page (see paragraph 4.4 ). The namesake method of class org.apache.wicket.Component is just a convenience method that internally invokes the actual implementation on current request cycle: public final void setResponsePage(final Page page) { getRequestCycle().setResponsePage(page); } RequestCycle's hook methods and listeners The RequestCycle comes with some hook methods which can be overridden to perform custom actions when request handling reaches a specific stage. These methods are: onBeginRequest(): called when the RequestCycle is about to start handling the request. onEndRequest(): called when the RequestCycle has finished to handle the request onDetach(): called after the request handling has completed and the RequestCycle is about to be detached from its thread. The default implementation of this method invokes detach() on the current session (the Session class will be shortly discussed in paragraph 9.4). Methods onBeforeRequest and onEndRequest can be used if we need to execute custom actions before and after business code is executed, such as opening a Hibernate/JPA session and closing it when code has terminated. A more flexible way to interact with the request processing is to use the listener interface org.apache.wicket.request.cycle.IRequestCycleListener. In addition to the three methods already seen for RequestCycle, this interface offers further hooks into request processing: onBeginRequest(RequestCycle cycle): (see the description above) onEndRequest(RequestCycle cycle): (see the description above) onDetach(RequestCycle cycle): (see the description above) onRequestHandlerResolved(RequestCycle cycle, IRequestHandler handler): called when an IRequestHandler has been resolved. onRequestHandlerScheduled(RequestCycle cycle, IRequestHandler handler): called when an IRequestHandler has been scheduled for execution. onRequestHandlerExecuted(RequestCycle cycle, IRequestHandler handler): called when an IRequestHandler has been executed. onException(RequestCycle cycle, Exception ex): called when an exception has been thrown during request processing. onExceptionRequestHandlerResolved(RequestCycle rc, IRequestHandler rh, Exception ex): called when an IRequestHandler has been resolved and will be used to handle an exception. onUrlMapped(RequestCycle cycle, IRequestHandler handler, Url url): called when an URL has been generated for an IRequestHandler object. 43 To use the request cycle listeners we must add them to our application which in turn will pass them to the new RequestCycle's instances created with createRequestCycle method: @Override public void init() { super.init(); IRequestCycleListener myListener; //listener initialization… getRequestCycleListeners().add(myListener) } The getRequestCycleListeners method returns an instance of class org.apache.wicket.request.cycle.RequestCycleListenerCollection. This class is a sort of typed collection for IRequestCycleListener and it also implements the Composite pattern . 9.4 Session Class In Wicket we use class org.apache.wicket.Session to handle session-relative informations such as client informations, session attributes, session-level cache (seen in paragraph 8.2), etc... In addition, we know from paragraph 8.1 that Wicket creates a user session to store versions of stateful pages. Similarly to what happens with RequestCycle, the new Session's instances are generated by the Application class with the newSession(Request request, Response response) method. This method is not declared as final, hence it can be overridden if we need to use a custom implementation of the Session class. By default if our custom application class is a subclass of WebApplication, method newSession will return an instance of class org.apache.wicket.protocol.http.WebSession. As we have mentioned talking about RequestCycle, also class Session provides a static get() method which returns the session associated to the current thread. Session and listeners Similar to the RequestCycle, class org.apache.wicket.Session also offers support for listener entities. With Session these entities must implement the callback interface org.apache.wicket.ISessionListener which exposes only the onCreated(Session session) method. As you might guess from its name, this method is called when a new session is created. Session listeners must be added to our application using a typed collection, just like we have done before with request cycle listeners: @Override public void init(){ super.init(); //listener initialization… ISessionListener myListener; //add a custom session listener getSessionListeners().add(myListener) } Handling session attributes The Session class handles session attributes in much the same way as the standard interface javax.servlet.http.HttpSession. The following methods are provided to create, read and remove session attributes: setAttribute(String name, Serializable value): creates an attribute identified by the given name. If the session already contains an attribute with the same name, the new value will replace the existing one. The value must be a serializable object. getAttribute(String name): returns the value of the attribute identified by the given name, or null if the name does not correspond to any attribute. 44 removeAttribute(String name): removes the attribute identified by the given name. By default class WebSession will use the underlying HTTP session to store attributes. Wicket will automatically add a prefix to the name of the attributes. This prefix is returned by the WebApplication's method getSessionAttributePrefix(). Accessing to the HTTP session If for any reason we need to directly access to the underlying HttpSession object, we can retrieve it from the current request with the following code: HttpSession session = ((ServletWebRequest)RequestCycle.get() .getRequest()).getContainerRequest().getSession(); Using the raw session object might be necessary if we have to set a session attribute with a particular name without the prefix added by Wicket. Let's say for example that we are working with Tomcat as web server. One of the administrative tools provided by Tomcat is a page listing all the active user sessions of a given web application: Tomcat allows us to set the values that will be displayed in columns “Guessed locale” and “Guessed User name”. One possible way to do this is to use session attributes named “Locale” and “userName” but we can't create them via Wicket's Session class because they would not have exactly the name required by Tomcat. Instead, we must use the raw HttpSession and set our attributes on it: HttpSession session = ((ServletWebRequest)RequestCycle.get(). getRequest()).getContainerRequest().getSession(); session.setAttribute("Locale", "ENGLISH"); session.setAttribute("userName", "Mr BadGuy"); Temporary and permanent sessions Wicket doesn't need to store data into user session as long as the user visits only stateless pages. Nonetheless, even under these conditions, a temporary session object is created to process each request but it is discarded at the end of the current request. To know if the current session is temporary, we can use the isTemporary() method: Session.get().isTemporary(); 45 If a session is not temporary (i.e. it is permanent), it's identified by an unique id which can be read calling the getId() method. This value will be null if the session is temporary. Although Wicket is able to automatically recognize when it needs to replace a temporary session with a permanent one, sometimes we may need to manually control this process to make our initially temporary session permanent. To illustrate this possible scenario let's consider project BindSessionExample where we have a stateless home page which sets a session attribute inside its constructor and then it redirects the user to another page which displays with a label the session attribute previously created. The code of the two pages is as follows: Home page: public class HomePage extends WebPage { public HomePage(final PageParameters parameters) { Session.get().setAttribute( "username", "tommy"); Session.get().bind(); setResponsePage(DisplaySessionParameter.class); } } Target page: public class DisplaySessionParameter extends WebPage { public DisplaySessionParameter() { super(); add(new Label("username", (String) Session.get().getAttribute("username"))); } } Again, we kept page logic very simple to not over-bloat the example with unnecessary code. In the snippet above we have also bolded Session's bind() method which converts temporary session into a permanent one. If the home page has not invoked this method, the session with its attribute would have been discarded at the end of the request and the page DisplaySessionParameter would have displayed an empty value in its label. Discarding session data Once a user has finished using our web application, she must be able to log out and clean any session data. To be sure that a permanent session will be discarded at the end of the current request, class Session provides the invalidate() method. If we want to immediately invalidate a given session without waiting for the current request to complete, we can invoke the invalidateNow() method. Remember that invalidateNow() will immediately remove any instance of components (and pages) from the session, meaning that once we have called this method we won't be able to work with them for the rest of the request process. Storing arbitrary objects with metadata JavaServer Pages Specification1 defines 4 scopes in which a page can create and access a variable. These scopes are: request: variables declared in this scope can be seen only by pages processing the same request. The lifespan of these variables is (at most) equal to the one of the related request. They are discarded when the full response has been generated or when the request is forwarded somewhere else. page: variables declared in this scope can be seen only by the page that has created them. session: variables in session scope can be created and accessed by every page used in the same session where they are defined. 46 application: this is the widest scope. Variables declared in this scope can be used by any page of a given web application. Although Wicket doesn't implement the JSP Specification (it is rather an alternative to it), it offers a feature called metadata which resembles scoped variables but is much more powerful. Metadata is quite similar to a Java Map in that it stores pairs of key-value objects where the key must be unique. In Wicket each of the following classes has its own metadata store: RequestCycle, Session, Application and Component. The key used for metadata is an instance of class org.apache.wicket.MetaDataKey. To put an arbitrary object into metadata we must use the setMetaData method which takes two parameters as input: the key used to store the value and the value itself. If we are using metadata with classes Session or Component, data object must be serializable because Wicket serializes both session and component instances. This constraint is not applied to metadata of classes Application and RequestCycle which can contain a generic object. In any case, the type of data object must be compatible with the type parameter T specified by the key. To retrieve a previously inserted object we must use the getMetaData(MetaDataKey key) method. In the following example we set a java.sql.Connection object in the application's metadata so it can be used by any page of the application: Application class code: public static MetaDataApp extends WebApplication{ //Do some stuff… /** * Metadata key definition */ public static MetaDataKey connectionKey = new MetaDataKey (){}; /** * Application's initialization */ @Override public void init(){ super.init(); Connection connection; //connection initialization… setMetaData(connectionKey, connection); //Do some other stuff.. } } Code to get the object from the metadata: Connection connection = Application.get().getMetaData(MetaDataApp.connectionKey); Since MetaDataKey class is declared as abstract, we must implement it with a subclass or with an anonymous class (like we did in the example above). 9.5 Exception handling Wicket uses a number of custom exceptions during the regular running of an application. We have already seen PageExpiredException raised when a page version is expired. Other examples of such exceptions are AuthorizationException and RestartResponseException. We will see them later in the next chapters. All the other exceptions raised during rendering phase are handled by an implementation of org.apache.wicket.request.IExceptionMapper which by default is class org.apache.wicket.DefaultExceptionMapper. If we are working in DEVELOPMENT mode this mapper will redirect us to a page that shows the exception stacktrace (page ExceptionErrorPage). On the contrary, if application is running in DEPLOYMENT mode DefaultExceptionMapper will display an internal error page which by default is org.apache.wicket.markup.html.pages.InternalErrorPage. To use a custom internal error page we can change application settings like this: getApplicationSettings().setInternalErrorPage(MyInternalErrorPage.class); 47 We can also manually set if Wicket should display the exception with ExceptionErrorPage or if we want to use the internal error page or if we don't want to display anything at all when an unexpected exception is thrown: //show default developer page getExceptionSettings().setUnexpectedExceptionDisplay( IExceptionSettings.SHOW_EXCEPTION_PAGE ); //show internal error page getExceptionSettings().setUnexpectedExceptionDisplay( IExceptionSettings.SHOW_INTERNAL_ERROR_PAGE ); //show no exception page when an unexpected exception is thrown getExceptionSettings().setUnexpectedExceptionDisplay( IExceptionSettings.SHOW_NO_EXCEPTION_PAGE ); Developers can also decide to use a custom exception mapper instead of DefaultExceptionMapper. To do this we must override Application's method getExceptionMapperProvider: @Override public IProvider getExceptionMapperProvider() { //… } The method returns an instance of org.apache.wicket.util.IProvider that should return our custom exception mapper. Ajax requests To control the behavior in Ajax requests the application may use org.apache.wicket.settings.IExceptionSettings# setAjaxErrorHandlingStrategy(IExceptionSettings.AjaxErrorStrategy). By default if an error occurs during the processing of an Ajax request Wicket will render the configured error page. By configuring org.apache.wicket.settings.IExceptionSettings. AjaxErrorStrategy#INVOKE_FAILURE_HANDLER as the default strategy the application will call the JavaScript onFailure callback(s) instead. 9.6 Summary In this chapter we had a look at how Wicket internally handles a web request. Even if most of the time we won't need to customize this internal process, knowing how it works is essential to use the framework at 100%. Entities like Application and Session will come in handy again when we will tackle the topic of security in chapter 21. 48 10 Wicket Links and URL generation Up to now we used component Link to move from a page to another and we have seen that it is quiet similar to a “click” event handler (see paragraph 4.4). However this component alone is not enough to build all possible kinds of links we may need in our pages. Therefore, Wicket offers other link components suited for those tasks which can not be accomplished with a basic Link. Besides learning new link components, in this chapter we will also see how to customize the page URL generated by Wicket using the encoding facility provided by the framework and the page parameters that can be passed to a target page. 10.1 PageParameters A common practice in web development is to pass data to a page using query string parameters (like ?paramName1=paramValu1¶mName2=paramValue2...). Wicket offers a more flexible and object oriented way to do this with models (we will see them in the next chapter). However, even if we are using Wicket, we still need to use query string parameters to exchange data with other Internet-based services. Consider for example a classic confirmation page which is linked inside an email to let users confirm important actions like password changing or the subscription to a mailing list. This kind of page usually expects to receive a query string parameter containing the id of the action to confirm. Query string parameters can also be referred to as named parameters. In Wicket they are handled with class org.apache.wicket.request.mapper.parameter.PageParameters. Since named parameters are basically name-value pairs, PageParameters works in much the same way as Java Map providing two methods to create/modify a parameter (add(String name, Object value) and set(String name, Object value)), one method to remove an existing parameter (remove(String name)) and one to retrieve the value of a given parameter (get(String name)) . Here is a snippet to illustrate the usage of PageParameters: PageParameters pageParameters = new PageParameters(); //add a couple of parameters pageParameters.add("name", "John"); pageParameters.add("age", 28); //retrieve the value of 'age' parameter pageParameters.get("age"); Now that we have seen how to work with page parameters, let's see how to use them with our pages. PageParameters and bookmarkable pages Base class Page comes with a constructor which takes as input a PageParameters instance. If we use this superclass constructor in our page, PageParameters will be used to build the page URL and it can be retrieved at a later time with the Page's getPageParameters() method. In the following example taken from the PageParametersExample project we have a home page with a link to a second page that uses a version of setResponsePage method that takes as input also a PageParameters to build the target page (named PageWithParameters). The code for the link and for the target page is the following: Link code: add(new Link("pageWithIndexParam") { @Override 49 public void onClick() { PageParameters pageParameters = new PageParameters(); pageParameters.add("foo", "foo"); pageParameters.add("bar", "bar"); setResponsePage(PageWithParameters.class, pageParameters); } }); Target page code: public class PageWithParameters extends WebPage { //Override superclass constructor public PageWithParameters(PageParameters parameters) { super(parameters); } } The code is quite straightforward and it’s more interesting to look at the URL generated for the target page: /PageParametersExample/wicket/bookmarkable/ org.wicketTutorial.PageWithParameters?foo=foo&bar=bar At first glance the URL above could seem a little weird, except for the last part which contains the two named parameters used to build the target page. The reason for this “strange” URL is that, as we explained in paragraph 8.3, when a page is instantiated using a constructor with no argument or using a constructor that accepts only a PageParameters, Wicket will try to generate a static URL for it, with no session-relative informations. This kind of URL is called bookmarkable because it can be saved by the users as a bookmark and accessed at a later time. A bookmarkable URL is composed by a fixed prefix (which by default is bookmarkable) and the qualified name of the page class (org.wicketTutorial.PageWithParameters in our example). Segment wicket is another fixed prefix added by default during URL generation. In paragraph 10.6 we will see how to customize fixed prefixes with a custom implementation of IMapperContext interface. Indexed parameters Besides named parameters, Wicket also supports indexed parameters. These kinds of parameters are rendered as URL segments placed before named parameters. Let's consider for example the following URL: /foo/bar?1&baz=baz The URL above contains two indexed parameters (foo and bar) and a query string consisting of the page id and a named parameter (baz). Just like named parameters also indexed parameters are handled by the PageParameters class. The methods provided by PageParameters for indexed parameters are set(int index, Object object) (to add/modify a parameter), remove(int index)(to remove a parameter) and get(int index) (to read a parameter). As their name suggests, indexed parameters are identified by a numeric index and they are rendered following the order in which they have been added to the PageParameters. The following is an example of indexed parameters: PageParameters pageParameters = new PageParameters(); //add a couple of parameters pageParameters.set(0, "foo"); pageParameters.set(1, "bar"); //retrieve the value of the second parameter ("bar") pageParameters.get(1); 50 Project PageParametersExample comes also with a link to a page with both indexed parameters and a named parameter: add(new Link("pageWithNamedIndexParam") { @Override public void onClick() { PageParameters pageParameters = new PageParameters(); pageParameters.set(0, "foo"); pageParameters.set(1, "bar"); pageParameters.add("baz", "baz"); setResponsePage(PageWithParameters.class, pageParameters); } }); The URL generated for the linked page (PageWithParameters) is the one seen at the beginning of the paragraph. 10.2 Bookmarkable links A link to a bookmarkable page can be built with org.apache.wicket.markup.html.link.BookmarkablePageLink: the link component BookmarkablePageLink bpl=new BookmarkablePageLink(PageWithParameters.class, pageParameters); The specific purpose of this component is to provide an anchor to a bookmarkable page, hence we don't have to implement any abstract method like we do with Link component. 10.3 Automatically creating bookmarkable links with tag wicket:link Bookmarkable pages can be linked directly inside markup files without writing any Java code. Using tag we ask Wicket to automatically add bookmarkable links for the anchors wrapped inside it. Here is an example of usage of tag taken from the home page of the project BookmarkablePageAutoLink: Apache Wicket Quickstart The key part of the markup above is the href attribute which must contain the package-relative path to a page. The home page is inside package org.wicketTutorial which in turns contains the sub package anotherPackage. This package hierarchy is reflected by the href attributes: in the first anchor we have a link to the home page itself while the second anchor points to page SubPackagePage which is placed into sub package anotherPackage. Absolute paths are supported as well and we can use them if we want to specify the full package of a given page. For example the link to SubPackagePage could have been written in the following (more verbose) way: SubPackagePage 51 If we take a look also at the markup of SubPackagePage we can see that it contains a link to the home page which uses the parent directory selector (relative path): Apache Wicket Quickstart Please note that any link to the current page (aka self link) is disabled. For example in the home page the self link is rendered like this: HomePage The markup used to render disabled links can be customized using the markup settings (interface IMarkupSettings) available in the application class: @Override public void init() { super.init(); //wrap disabled links with tag getMarkupSettings().setDefaultBeforeDisabledLink(""); getMarkupSettings().setDefaultAfterDisabledLink(""); } The purpose of tag is not limited to just simplifying the usage of bookmarkable pages. As we will see in chapter 13, this tag can also be adopted to manage web resources like pictures, CSS files, JavaScript files and so on. 10.4 External links Since Wicket uses plain HTML markup files as templates, we can place an anchor to an external page directly inside the markup file. When we need to dynamically generate external anchors, we can use link component org.apache.wicket.markup.html.link.ExternalLink. In order to build an external link we must specify the value of the href attribute using a model or a plain string. In the next snippet, given an instance of Person, we generate a Google search query for its full name: Html: Search me on Google! Java code: Person person = new Person("John", "Smith"); String fullName = person.getFullName(); //Space characters must be replaced by character '+' String googleQuery = "http://www.google.com/search?q=" + fullName.replace(" ", "+"); add(new ExternalLink("externalSite", googleQuery)); Generated anchor: 52 Search me on Google! If we need to specify a dynamic value for the text inside the anchor, we can pass it as an additional constructor parameter: Html: Label goes here... Java code: Person String String String person = new Person("John", "Smith"); fullName = person.getFullName(); googleQuery = "http://www.google.com/search?q=" + fullName.replace(" ", "+"); linkLabel = "Search '" + fullName + "' on Google."; add(new ExternalLink("externalSite", googleQuery, linkLabel)); Generated anchor: Search 'John Smith' on Google. 10.5 Stateless links Component Link has a stateful nature, hence it cannot be used with stateless pages. To use links with these kinds of pages Wicket provides the convenience org.apache.wicket.markup.html.link.StatelessLink component which is basically a subtype of Link with the stateless hint set to true. Please keep in mind that Wicket generates a new instance of a stateless page also to serve stateless links, so the code inside the onClick() method can not depend on instance variables. To illustrate this potential issue let's consider the following code (from the project StatelessPage) where the value of the variable index is used inside onclick(): public class StatelessPage extends WebPage { private int index = 0; public StatelessPage(PageParameters parameters) { super(parameters); } @Override protected void onInitialize() { super.onInitialize(); setStatelessHint( true); add(new StatelessLink("statelessLink") { @Override public void onClick() { //It will always print zero System.out.println(index++); } }); } } The printed value will always be zero because a new instance of the page is used every time the user clicks on the statelessLink link. 10.6 Generating structured and clear URLs 53 Having structured URLs in our site is a basic requirement if we want to build an efficient SEO strategy, but it also contributes to improve user experience with more intuitive URLs. Wicket provides two different ways to control URL generation. The first (and simplest) is to “mount” one or more pages to an arbitrary path, while a more powerful technique is to use custom implementations of IMapperContext and IPageParametersEncoder interfaces. In the next paragraphs we will learn both of these two techniques. Mounting a single page With Wicket we can mount a page to a given path in much the same way as we map a servlet filter to a desired path inside file web.xml (see paragraph 4.2). Using mountPage(String path, Class pageClass) method of the WepApplication class we tell Wicket to respond with a new instance of pageClass whenever a user navigates to the given path. In the application class of the project MountedPagesExample we mount MountedPage to the "/pageMount" path: @Override public void init() { super.init(); mountPage("/pageMount", MountedPage.class); //Other initialization code… } The path provided to mountPage will be used to generate the URL for any page of the specified class: //it will return "/pageMount" RequestCycle.get().urlFor(MountedPage.class); Under the hood the mountPage method mounts an instance of the request org.apache.wicket.request.mapper.MountedMapper configured for the given path: mapper public final void mountPage(final String path,final Class pageClass) { mount(new MountedMapper(path, pageClass)); } Request mappers and the Application's method mount have been introduced in the previous chapter (paragraph 9.3). Using parameter placeholders with mounted pages The path specified for mounted pages can contain dynamic segments which are populated with the values of the named parameters used to build the page. These segments are declared using special segments called parameter placeholders. Consider the path used in the following example: mountPage("/pageMount/${foo}/otherSegm", MountedPageWithPlaceholder.class); The path used above is composed by three segments: the first and the last are fixed while the second will be replaced by the value of the named parameter foo that must be provided when the page MountedPageWithPlaceholder is instantiated: Java code: PageParameters pageParameters = new PageParameters(); pageParameters.add("foo", "foo"); setResponsePage(MountedPageWithPlaceholder.class, pageParameters) 54 Generated URL: /pageMount/foo/otherSegm On the contrary if we manually insert an URL like '/pageMount/bar/otherSegm', we can read value 'bar' retrieving the named parameter foo inside our page. Place holders can be declared as optional using the '#' character in place of '$': mountPage("/pageMount/#{foo}/otherSegm", MountedPageOptionalPlaceholder.class); If the named parameter for an optional placeholder is missing, the corresponding segment is removed from the final URL: Java code: PageParameters pageParameters = new PageParameters(); setResponsePage(MountedPageWithPlaceholder.class, pageParameters); Generated URL: /pageMount/otherSegm Mounting a package In addition to mounting a single page, Wicket allows to mount all of the pages inside a package to a given path. Method mountPackage(String path, Class pageClass) of class WepApplication will mount every page inside pageClass's package to the specified path. The resulting URL for package-mounted pages will have the following structure: /mountedPath/[optional query string] For example in the MountedPagesExample project we have mounted all pages inside the subpackage org.tutorialWicket.subPackage with this line of code: mountPackage("/mountPackage", StatefulPackageMount.class); StatefulPackageMount is one of the pages placed into the desired package and its URL will be: /mountPackage/StatefulPackageMount?1 Similarly to what is done by the mountPage method, the implementation of the mountPackage method mounts an instance of org.apache.wicket.request.mapper.PackageMapper to the given path. Providing custom mapper context to request mappers Interface org.apache.wicket.request.mapper.IMapperContext is used by request mappers to create new page instances and to retrieve static URL segments used to build and parse page URLs. Here is the list of these segments: 55 Namespace: it's the first URL segment of non-mounted pages. By default its value is wicket. Identifier for non-bookmarkable URLs: it's the segment that identifies non bookmarkable pages. By default its value is page. Identifier for bookmarkable URLs: it's the segment that identifies bookmarkable pages. By default its value is bookmarkable (as we have seen before in paragraph 10.1.1). Identifier for resources: it's the segment that identifies Wicket resources. Its default value is resources. The topic of resource management will be covered in chapter 15. IMapperContext provides a getter method for any segment listed above. By default Wicket uses class org.apache.wicket.DefaultMapperContext as mapper context. Project CustomMapperContext is an example of customization of mapper context where we use index as identifier for non-bookmarkable pages and staticURL as identifier for bookmarkable pages. In this project, instead of implementing our mapper context from scratch, we used DefaultMapperContext as base class overriding just the two methods we need to achieve the desired result (getBookmarkableIdentifier() and getPageIdentifier()). The final implementation is the following: public class CustomMapperContext extends DefaultMapperContext{ @Override public String getBookmarkableIdentifier() { return "staticURL"; } @Override public String getPageIdentifier() { return "index"; } } Now to use a custom mapper context in our application we must override the newMapperContext() method declared in the Application class and make it return our custom implementation of IMapperContext: @Override protected IMapperContext newMapperContext() { return new CustomMapperContext(); } Controlling how page parameters are encoded with IPageParametersEncoder Some request mappers (like MountedMapper and PackageMapper) can delegate page parameters encoding/decoding to interface org.apache.wicket.request.mapper.parameter.IPage ParametersEncoder . This entity exposes two methods: encodePageParameters() and decodePageParameters(): the first one is invoked to encode page parameters into an URL while the second one extracts parameters from the URL. Wicket comes with a built-in implementation of this interface which encodes named page parameters as URL segments using the following pattern: /paramName1/paramValue1/paramName2/param Value2... This built-in encoder is org.apache.wicket.request.mapper.parameter.UrlPathPageParametersEncoder class. In the PageParametersEncoderExample project we have manually mounted a MountedMapper that takes as input also an UrlPathPageParametersEncoder: @Override public void init() { super.init(); mount(new MountedMapper("/mountedPath", MountedPage.class, new UrlPathPageParametersEncoder())); } 56 The home page of the project contains just a link to the MountedPage web page. The code of the link and the resulting page URL are: Link code: add(new Link("mountedPage") { @Override public void onClick() { PageParameters pageParameters = new PageParameters(); pageParameters.add("foo", "foo"); pageParameters.add("bar", "bar"); setResponsePage(MountedPage.class, pageParameters); } }); Generated URL: /mountedPath/foo/foo/bar/bar?1 Encrypting page URLs Sometimes URLs are a double–edged sword for our site because they can expose too many details about the internal structure of our web application making it more vulnerable to malicious users. To avoid this kind of security threat we can use the CryptoMapper request mapper which wraps an existing mapper and encrypts the original URL producing a single encrypted segment: Typically, CryptoMapper is registered into a Wicket application as the root request mapper wrapping the default one: @Override public void init() { super.init(); setRootRequestMapper(new CryptoMapper(getRootRequestMapper(), this)); //pages and resources must be mounted after we have set CryptoMapper mountPage("/foo/", HomePage.class); As pointed out in the code above, pages and resources must be mounted after having set CryptoMapper as root mapper, otherwise the mounted paths will not work. By default CryptoMapper encrypts page URLs with a cipher that might not be strong enough for production environment. Paragraph 21.4 will provide a more detailed description of how Wicket encrypts page URLs and we will see how to use stronger ciphers. 10.7 Summary Links and URLs are not trivial topics as they may seem and in Wicket they are strictly interconnected. Developers must choose the right trade-off between producing structured URLs and avoiding to make them verbose and vulnerable. In this chapter we have explored the tools provided by Wicket to control how URLs are generated. We have started with static URLs for bookmarkable pages and we have seen how to pass parameters to target pages with 57 PageParameters. In the second part of the chapter we focused on mounting pages to a specific path and on controlling how parameters are encoded by Wicket. Finally, we have also seen how to encrypt URLs to prevent security vulnerabilities. 58 11 Wicket models and forms In Wicket the concept of “model” is probably the most important topic of the entire framework and it is strictly related to the usage of its components. In addition, models are also an important element for internationalization, as we will see in paragraph 12.6. However, despite their fundamental role, in Wicket models are not difficult to understand but the best way to learn how they work is to use them with forms. That's why we haven't talked about models so far, and why this chapter discusses these two topics together. 11.1 What is a model? Model is essentially a facade interface which allows components to access and modify their data without knowing any detail about how they are managed or persisted. Every component has at most one related model, while a model can be shared among different components. In Wicket a model is any implementation of the interface org.apache.wicket.model.IModel: The IModel interface defines just the methods needed to get and set a data object (getObject() and setObject()), decoupling components from concrete details about the persistence strategy adopted for data. In addition, the level of indirection introduced by models allows access data object only when it is really needed (for example during the rendering phase) and not earlier when it may not be ready to be used. Any component can get/set its model as well as its data object using the 4 public shortcut methods listed in the class diagram above. The two methods onModelChanged() and onModelChanging() are triggered by Wicket each time a model is modified: the first one is called after the model has been changed, the second one just before the change occurs. In the examples seen so far we have worked with Label component using its constructor which takes as input two string parameters, the component id and the text to display: add(new Label("helloMessage", "Hello WicketWorld!")); This constructor internally builds a model which wraps the second string parameter. That's why we didn't mention label model in the previous examples. Here is the code of this constructor: public Label(final String id, String label) { this(id, new Model(label)); } Class org.apache.wicket.model.Model is a basic implementation of IModel. It can wrap any object that implements the interface java.io.Serializable. The reason of this constraint over data object is that this model is stored in the web session, and we know from chapter 6 that data are stored into session using serialization. In general, Wicket models support a detaching capability that allows us to work also with non-serializable objects as data model. We will see the detaching mechanism later in this chapter. 59 Just like any other Wicket components, Label provides a constructor that takes as input the component id and the model to use with the component. Using this constructor the previous example becomes: add(new Label("helloMessage", new Model("Hello WicketWorld!"))); The Model class comes with a bunch of factory methods that makes it easier to build new model instances. For example the of(T object) method creates a new instance of Model which wraps any Object instance inside it. So instead of writing new Model("Hello WicketWorld!") we can write Model.of("Hello WicketWorld!") If the data object is a List, a Map or a Set we can use similar methods called ofList, ofMap and ofSet. From now on we will use these factory methods in our examples. It's quite clear that if our Label must display a static text it doesn't make much sense to build a model by hand like we did in the last code example. However is not unusual to have a Label that must display a dynamic value, like the input provided by a user or a value read from a database. Wicket models are designed to solve these kinds of problems. Let's say we need a label to display the current time stamp each time a page is rendered. We can implement a custom model which returns a new Date instance when the getObject() method is called: IModel timeStampModel = new Model(){ @Override public String getObject() { return new Date().toString(); } }; add(new Label("timeStamp", timeStampModel)); Even if sometimes writing a custom model could be a good choice to solve a specific problem, Wicket already provides a set of IModel implementations which should fit most of our needs. In the next paragraph we will see a couple of models that allow us to easily integrate JavaBeans with our web applications and in particular with our forms. By default the class Component escapes HTML sensitive characters (like '<', '>' or '&') from the textual representation of its model object. The term 'escape' means that these characters will be replaced with their corresponding HTML entity (for example '<' becomes '< '). This is done for security reasons as a malicious user could attempt to inject markup or JavaScript into our pages. If we want to display the raw content stored inside a model, we can tell the Component class not to escape characters by calling the setEscapeModelStrings(false) method. 11.2 Models and JavaBeans One of the main goals of Wicket is to use JavaBeans and POJO as data model, overcoming the impedance mismatch between web technologies and OO paradigm. In order to make this task as easy as possible, Wicket offers two special model classes: org.apache.wicket.model.PropertyModel and org.apache.wicket.model.CompoundPropertyModel. We will see how to use them in the next two examples, using the following JavaBean as the data object: public class Person implements Serializable { private String name; private String surname; private String address; private String email; private String passportCode; 60 private Person spouse; private List children; public Person(String name, String surname) { this.name = name; this.surname = surname; } public String getFullName(){ return name + " " + surname; } /* * Getters and setters for private fields */ } PropertyModel Let's say we want to display the name field of a Person instance with a label. We could, of course, use the Model class like we did in the previous example, obtaining something like this: Person person = new Person(); //load person's data... Label label = new Label("name", new Model(person.getName())); However this solution has a huge drawback: the text displayed by the label will be static and if we change the value of the field, the label won't update its content. Instead, to always display the current value of a class field, we should use the org.apache.wicket.model.PropertyModel model class: Person person = new Person(); //load person's data... Label label = new Label("name", new PropertyModel(person, "name")); PropertyModel has just one constructor with two parameters: the model object (person in our example) and the name of the property we want to read/write ("name" in our example). This last parameter is called property expression. Internally, methods getObject/setObject use property expression to get/set property's value. To resolve class properties PropertyModel uses class org.apache.wicket.util.lang.Property Resolver which can access any kind of property, private fields included. Just like the Java language, property expressions support dotted notation to select sub properties. So if we want to display the name of the Person's spouse we can write: Label label = new Label("spouseName", new PropertyModel(person, "spouse.name")); PropertyModel is null-safe, which means we don't have to worry if property expression includes a null value in its path. If such a value is encountered, an empty string will be returned. If property is an array or a List, we can specify an index after its name. For example, to display the name of the first child of a Person we can write the following property expression: Label label = new Label("firstChildName", new PropertyModel(person, "children.0.name")); Indexes and map keys can be also specified using squared brackets: 61 children[0].name … mapField[key].subfield ... CompoundPropertyModel and model inheritance Class org.apache.wicket.model.CompoundPropertyModel is a particular kind of model which is usually used in conjunction with another Wicket feature called model inheritance. With this feature, when a component needs to use a model but none has been assigned to it, it will search through the whole container hierarchy for a parent with an inheritable model. Inheritable models are those which implement interface org.apache.wicket.model.IComponentInheritedModel and CompoundPropertyModel is one of them. Once a CompoundPropertyModel has been inherited by a component, it will behave just like a PropertyModel using the id of the component as property expression. As a consequence, to make the most of CompoundPropertyModel we must assign it to one of the containers of a given component, rather than directly to the component itself. For example if we use CompoundPropertyModel with the previous example (display spouse's name), the code would become like this: //set CompoundPropertyModel as model for the container of the label setDefaultModel(new CompoundPropertyModel(person)); Label label = new Label("spouse.name"); add(label); Note that now the id of the label is equal to the property expression previously used with PropertyModel. Now as a further example let's say we want to extend the code above to display all of the main informations of a person (name, surname, address and email). All we have to do is to add one label for every additional information using the relative property expression as component id: //Create a person named 'John Smith' Person person = new Person("John", "Smith"); setDefaultModel(new CompoundPropertyModel(person)); add(new add(new add(new add(new add(new Label("name")); Label("surname")); Label("address")); Label("email")); Label("spouse.name")); CompoundPropertyModel can save us a lot of boring coding if we choose the id of components according to properties name. However it's also possible to use this type of model even if the id of a component does not correspond to a valid property expression. The method bind(String property) allows to create a property model from a given CompoundPropertyModel using the provided parameter as property expression. For example if we want to display the spouse's name in a label having "xyz" as id, we can write the following code: //Create a person named 'John Smith' Person person = new Person("John", "Smith"); CompoundPropertyModel compoundModel; setDefaultModel(compoundModel = new CompoundPropertyModel(person)); add(new Label("xyz", compoundModel.bind("spouse.name"))); CompoundPropertyModel are particularly useful when used in combination with Wicket forms, as we will see in the next paragraph. Model is referred to as static model because the result of its method getObject is fixed and it is not dynamically evaluated each time the method is called. In contrast, models like PropertyModel and CompoundProperty Model are called dynamic models. 11.3 Wicket forms 62 11.3 Wicket forms Web applications use HTML forms to collect user input and send it to the server. Wicket provides org.apache.wicket.markup.html.form.Form class to handle web forms. This component must be bound to
tag. The following snippet shows how to create a very basic Wicket form in a page: Html:
Java code: Form form = new Form("form"){ @Override protected void onSubmit() { System.out.println("Form submitted."); } }; add(form); Method onSubmit is called whenever a form has been submitted and it can be overridden to perform custom actions. Please note that a Wicket form can be submitted using a standard HTML submit button which is not mapped to any component (i.e. it does not have a wicket:id attribute). In the next chapter we will continue to explore Wicket forms and we will see how to submit forms using special components which implement interface org.apache.wicket.markup.html.form.IFormSubmitter. Form and models A form should contain some input fields (like text fields, check boxes, radio buttons, drop-down lists, text areas, etc.) to interact with users. Wicket provides an abstraction for all these kinds of elements with component org.apache.wicket.markup.html.form.FormComponent: The purpose of FormComponent is to store the corresponding user input into its model when the form is submitted. The form is responsible for mapping input values to the corresponding components, avoiding us the burden of manually synchronizing models with input fields and vice versa. Login form As first example of interaction between the form and its models, we will build a classic login form which asks for username and password (project LoginForm). 63 The topic of security will be discussed later in chapter 20. The following form is for example purposes only and is not suited for a real application. If you need to use a login form you should consider to use component org.apache.wicket.authroles.authentication.panel.SignInPanel shipped with Wicket. This form needs two text fields, one of which must be a password field. We should also use a label to display the result of login process1. For the sake of simplicity, the login logic is all inside onSubmit and is quite trivial. The following is a possible implementation of our form: public class LoginForm extends Form { private TextField usernameField; private PasswordTextField passwordField; private Label loginStatus; public LoginForm(String id) { super(id); usernameField = new TextField("username", Model.of("")); passwordField = new PasswordTextField("password", Model.of("")); loginStatus = new Label("loginStatus", Model.of("")); add(usernameField); add(passwordField); add(loginStatus); } public final void onSubmit() { String username = (String)usernameField.getDefaultModelObject(); String password = (String)passwordField.getDefaultModelObject(); if(username.equals("test") && password.equals("test")) loginStatus.setDefaultModelObject( "Congratulations!"); else loginStatus.setDefaultModelObject( "Wrong username or password!"); } } Inside form's constructor we build the three components used in the form and we assign them a model containing an empty string: usernameField = new TextField("username", Model.of("")); passwordField = new PasswordTextField("password", Model.of("")); loginStatus = new Label("loginStatus", Model.of("")); If we don't provide a model to a form component, we will get the following exception on form submission: java.lang.IllegalStateException: Attempt to set model object on null model of component: Component TextField corresponds to the standard text field, without any particular behavior or restriction on the allowed values. We must bind this component to the tag with the attribute type set to "text". PasswordTextField is a subtype of TextFiled and it must be used with an tag with the attribute type set to"password". For security reasons component PasswordTextField cleans its value at each request, so it wil be always empty after the form has been rendered. By default PasswordTextField fields are required, meaning that if we left them empty, the form won't be submitted (i.e. onSubmit won't be called). Class FormComponent provides method setRequired(boolean required) to change this behavior. Inside onSubmit, to get/set model objects we have used shortcut methods setDefaultModelObject and getDefaultModelObject. Both methods are defined in class Component (see class diagram from Illustration 9.1). The following are the possible markup and code for the login page: Html: 64 Login page
Login

Username:
Password:

Java code: public class HomePage extends WebPage { public HomePage(final PageParameters parameters) { super(parameters); add(new LoginForm("loginForm")); } } The example shows how Wicket form components can be used to store user input inside their model. However we can dramatically improve the form code using CompoundPropertyModel and its ability to access the properties of its model object. The revisited code is the following (the LoginFormRevisited project): public class LoginForm extends Form{ private String username; private String password; private String loginStatus; public LoginForm(String id) { super(id); setDefaultModel( new CompoundPropertyModel(this)); add(new TextField("username")); add( new PasswordTextField("password")); add( new Label("loginStatus")); } public final void onSubmit() { if(username.equals("test") && password.equals("test")) loginStatus = "Congratulations!"; else loginStatus = "Wrong username or password !"; } } In this version the form itself is used as model object for its CompoundPropertyModel. This allows children components to have direct access to form fields and use them as backing objects, without explicitly creating a model for themselves. 65 Keep in mind that when CompoundPropertyModel is inherited, it does not consider the ids of traversed containers for the final property expression, but it will always use the id of the visited child. To understand this potential pitfall, let's consider the following initialization code of a page: //Create a person named 'John Smith' Person person = new Person("John", "Smith"); //Create a person named 'Jill Smith' Person spouse = new Person("Jill", "Smith"); //Set Jill as John's spouse person.setSpouse(spouse); setDefaultModel(new CompoundPropertyModel(person)); WebMarkupContainer spouseContainer = new WebMarkupContainer("spouse"); Label name; spouseContainer.add(name = new Label("name")); add(spouseContainer); The value displayed by label "name" will be "John" and not the spouse's name "Jill" as you may expect. In this example the label doesn't own a model, so it must search up its container hierarchy for an inheritable model. However, its container (WebMarkup Container with id 'spouse') doesn't own a model, hence the request for a model is forwarded to the parent container, which in this case is the page. In the end the label inherits CompoundPropertyModel from page but only its own id is used for the property expression. The containers in between are never taken into account for the final property expression. 11.4 Component DropDownChoice Class org.apache.wicket.markup.html.form.DropDownChoice is the form component needed to display a list of possible options as a drop-down list where users can select one of the proposed options. This component must be used with
Java code: List fruits = Arrays.asList("apple", "strawberry", "watermelon"); form.add(new DropDownChoice("fruits", new Model(), fruits)); Screenshot of generated page: In addition to the component id, in order to build a DropDownChoice we need to provide to its constructor two further parameters: a model containing the current selected item. This parameter is not required if we are going to inherit a CompoundPropertyModel for this component. a list of options to display which can be supplied as a model or as a regular java.util.List. 66 In the example above the possible options are provided as a list of String objects. Now let's take a look at the markup generated for them: The first option is a placeholder item corresponding to a null model value. By default DropDownChoice cannot have a null value so users are forced to select a not-null option. If we want to change this behavior we can set the nullValid flag to true via the setNullValid method. Please note that the placeholder text (“Chose one”) can be localized, as we will see in chapter 14. The other options are identified by the attribute value. By default the value of this attribute is the index of the single option inside the provided list of choices, while the text displayed to the user is obtained by calling toString()on the choice object. This default behavior works fine as long as our options are simple objects like strings, but when we move to more complex objects we may need to implement a more sophisticated algorithm to generate the value to use as the option id and the one to display to user. Wicket has solved this problem with org.apache.wicket.markup.html.form.IChoiceRender interface. This interface defines method getDisplayValue(T object) that is called to generate the value to display for the given choice object, and method getIdValue(T object, int index) that is called to generate the option id. The built-in implementation of this interface is class org.apache.wicket.markup.html.form.ChoiceRenderer which renders the two values using property expressions. In the following code we want to show a list of Person objects using their full name as value to display and using their passport code as option id: Java code: List persons; //Initialize the list of persons here… ChoiceRenderer personRenderer = new ChoiceRenderer("fullName", "passportCode"); form.add(new DropDownChoice("persons", new Model(), persons, personRenderer)); The choice renderer can be assigned to the DropDownChoice using one of its constructor that accepts this type of parameter (like we did in the example above) or after its creation invoking setChoiceRenderer method. 11.5 Model chaining Models that implement the interface org.apache.wicket.model.IChainingModel can be used to build a chain of models. These kinds of models are able to recognize whether their model object is itself an implementation of IModel and if so, they will call getObject on the wrapped model and the returned value will be the actual model object. In this way we can combine the action of an arbitrary number of models, making exactly a chain of models. Chaining models allows to combine different data persistence strategies, similarly to what we do with chains of I/O streams. To see model chaining in action we will build a page that implements the List/Detail View pattern, where we have a drop-down list of Person objects and a form to display and edit the data of the current selected Person. The example page will look like this: What we want to do in this example is to chain the model of the DropDownChoice (which contains the selected 67 Person) with the model of the Form. In this way the Form will work with the selected Person as backing object. The DropDownChoice component can be configured to automatically update its model each time we change the selected item on the client side. All we have to do is to override method wantOnSelectionChangedNotifications to make it return true. In practice, when this method returns true, DropDownChoice will submit its value every time JavaScript event onChange occurs, and its model will be consequently updated. To leverage this functionality, DropDownChoice doesn't need to be inside a form. The following is the resulting markup of the example page: … List of persons

Name:
Surname:
Address:
Email:
The initialization code for DropDownChoice is the following: Model listModel = new Model(); ChoiceRenderer personRender = new ChoiceRenderer("fullName"); personsList = new DropDownChoice("persons", listModel, loadPersons(), personRender){ @Override protected boolean wantOnSelectionChangedNotifications() { return true; } }; As choice render we have used the basic implementation provided with the org.apache.wicket .markup.html.form.ChoiceRenderer class that we have seen in the previous paragraph. loadPersons() is just an utility method which generates a list of Person instances. The model for DropDownChoice is a simple instance of the Model class. Here is the whole code of the page (except for the loadPersons() method): public class PersonListDetails extends WebPage { private Form form; private DropDownChoice personsList; public PersonListDetails(){ Model listModel = new Model(); ChoiceRenderer personRender = new ChoiceRenderer("fullName"); personsList = new DropDownChoice("persons", listModel, loadPersons(), personRender){ @Override protected boolean wantOnSelectionChangedNotifications() { 68 return true; } }; add(personsList); form = new Form("form", new CompoundPropertyModel(listModel)); form.add(new TextField("name")); form.add(new TextField("surname")); form.add(new TextField("address")); form.add(new TextField("email")); add(form); } //loadPersons() //… } The two models work together as a pipeline where the output of method getObject of Model is the model object of CompoundPropertyModel. As we have seen, model chaining allows us to combine the actions of two or more models without creating new custom implementations. 11.6 Detachable models In chapter 6 we have seen how Wicket uses serialization to store page instances. When an object is serialized, all its referenced objects are recursively serialized. For a page this means that all its children components, their related models as well as the model objects inside them will be serialized. For model objects this could be a serious issue for (at least) two main reasons: 1. The model object could be a very large instance, hence serialization would become very expensive in terms of time and memory. 2. We simply may not be able to use a serializable object as model object. In paragraphs 1.4 and 9.2 we stated that Wicket allows us to use a POJO as backing object, but POJOs are ordinary objects with no prespecified interface, annotation or superclass, hence they are not required to implement the standard Serializable interface. To cope with these problems IModel extends another interface called IDetachable. This interface provides a method called detach() which is invoked by Wicket at the end of web request processing when data model is no more needed but before serialization occurs. Overriding this method we can clean any reference to data object keeping just the information needed to retrieve it later (for example the id of the table row where our data are stored). In this way we can avoid the serialization of the object wrapped into the model overcoming both the problem with non-serializable objects and the one with large data objects. Since IModel inherits from IDetachable, every model of Wicket is “detachable”, although not all of them implement a detaching policy (like the Model class). Usually detaching operations are strictly dependent on the persistence technology adopted for model objects (like a relational db, a NoSQL db, a queue, etc), so it's not unusual to write a custom detachable model suited for the persistence technology chosen for a given project. To ease this task Wicket provides abstract model LoadableDetachableModel. This class internally holds a transient reference to a model object which is initialized the first time getObject()is called to precess a request. The 69 concrete data loading is delegated to abstract method T load(). The reference to a model object is automatically set to null at the end of the request by the detach() method. The following class diagram summarizes the methods defined inside LoadableDetachableModel. onDetach and onAttach can be overridden in order to obtain further control over the detaching procedure. Now as example of a possible use of LoadableDetachableModel, we will build a model designed to work with entities managed via JPA. To understand the following code a basic knowledge of JPA is required even if we won't go into the detail of this standard. The following model is provided for example purposes only and is not intended to be used in production environment. Important aspects such as transaction management are not taken into account and you should rework the code before considering to use it. public class JpaLoadableModel extends LoadableDetachableModel { private EntityManagerFactory entityManagerFactory; private Class entityClass; private Serializable identifier; private List constructorParams; public JpaLoadableModel(EntityManagerFactory entityManagerFactory, T entity) { super(); PersistenceUnitUtil util = entityManagerFactory.getPersistenceUnitUtil(); this.entityManagerFactory = entityManagerFactory; this.entityClass = (Class) entity.getClass(); this.identifier = (Serializable) util.getIdentifier(entity); setObject(entity); } @Override protected T load() { T entity = null; if(identifier != null) { EntityManager entityManager = entityManagerFactory.createEntityManager(); entity = entityManager.find(entityClass, identifier); } return entity; } @Override protected void onDetach() { super.onDetach(); T entity = getObject(); PersistenceUnitUtil persistenceUtil = entityManagerFactory.getPersistenceUnitUtil(); if(entity == null) return; identifier = (Serializable) persistenceUtil.getIdentifier(entity); } } The constructor of the model takes as input two parameters: an implementation of the JPA interface javax.persistence.EntityManagerFactory to manage JPA entities and the entity that must be handled by this 70 model. Inside its constructor the model saves the class of the entity and its id (which could be null if the entity has not been persisted yet). These two informations are required to retrieve the entity at a later time and are used by the load method. onDetach is responsible for updating the entity id before detachment occurs. The id can change the first time an entity is persisted (JPA generates a new id and assigns it to the entity). Please note that this model is not responsible for saving any changes occurred to the entity object before it is detached. If we don't want to loose these changes we must explicitly persist the entity before the detaching phase occurs. Since the model of this example holds a reference to the EntityManager Factory, the implementation in use must be serializable. 11.7 Using more than one model in a component Sometimes our custom components may need to use more than a single model to work properly. In such a case we must manually detach the additional models used by our components. In order to do this we can overwrite the Component's onDetach method that is called at the end of the current request. The following is the generic code of a component that uses two models: /** * * fooModel is used as main model while beeModel must be manually detached * */ public class ComponetTwoModels extends Component{ private IModel beeModel; public ComponetTwoModels(String id, IModel fooModel, IModel beeModel) { super(id, fooModel); this.beeModel = beeModel; } @Override public void onDetach() { if(beeModel != null) beeModel.detach(); super.onDetach(); } } When we overwrite onDetach we must call the super class implementation of this method, usually as last line in our custom implementation. 11.8 Use models! Like many people new to Wicket, you may need a little time to fully understand the power and the advantages of using models. Taking your first steps with Wicket you may be tempted to pass row objects to your components instead of using models: /** * * NOT TO DO: passing row objects to components instead of using models! * */ public class CustomComponent extends Component{ private FooBean fooBean; public CustomComponent(String id, FooBean fooBean) { super(id); this.fooBean = fooBean; } //...some other ugly code :)… } That's a bad practice and you must avoid it. Using models we do not only decouple our components from the data source, but we can also relay on them (if they are dynamic) to work with the most up-to-date version of our model object. If we decide to bypass models we lose all these advantages and we force model objects to be 71 serialized. 11.9 Summary Models are at the core of Wicket and they are the basic ingredient needed to taste the real power of the framework. In this chapter we have seen how to use models to bring data to our components without littering their code with technical details about their persistence strategy. We have also introduced Wicket forms as complementary topic. With forms and models we are able to bring our applications to life allowing them to interact with users. But what we have seen in this chapter about Wicket forms is just the tip of the iceberg. That's why the next chapter is entirely dedicated to them. 72 12 Wicket forms in detail In the previous chapter we have only scratched the surface of Wicket forms. The Form component was not only designed to collect user input but also to extend the semantic of the classic HTML forms with new features. One of such features is the ability to work with nested forms (they will be discussed in paragraph 12.6). In this chapter we will continue to explore Wicket forms learning how to master them and how to build effective and user-proof forms for our web applications. 12.1 Default form processing In paragraph 11.3 we have seen a very basic usage of the Form component and we didn't pay much attention to what happens behind the scenes of form submission. In Wicket when we submit a form we trigger the following steps on server side: 1. Form validation: user input is checked to see if it satisfies the validation rules set on the form. If validation fails, step number 2 is skipped and the form should display a feedback message to explain to user what went wrong. During this step input values (which are simple strings sent with a web request) are converted into Java objects. In the next paragraphs we will explore the infrastructures provided by Wicket for the three sub-tasks involved with form validation, which are: conversion of user input into objects, validation of user input, and visualization of feedback messages. 2. Updating of models: if validation succeeds, the form updates the model of its children components with the converted values obtained in the previous step. 3. Invoking callback methods onSubmit() or onError(): if we didn't have any validation error, method onSubmit() is called, otherwise onError() will be called. The default implementation of both these methods is left empty and we can override them to perform custom actions. Please note that the model of form components is updated only if no validation error occurred (i.e. step two is performed only if validation succeeds). Without going into too much detail, we can say that the first two steps of form processing correspond to the invocation of one or more Form's internal methods (which are declared protected and final). Some examples of these methods are validate(), which is invoked during validation step, and updateFormComponentModels(), which is used at the step that updates the form field models. The whole form processing is started invoking public method process(IFormSubmitter) (Later in paragraph 12.5 we will introduce interface IFormSubmitter). 12.2 Form validation and feedback messages A basic example of a validation rule is to make a field required. In paragraph 11.3 we have already seen how this can be done calling setRequired(true) on a field. However, to set a validation rule on a FormComponent we must add the corresponding validator to it. A validator is an implementation of the org.apache.wicket.validation.IValidator interface and the FormComponent has a version of method add which takes as input a reference of this interface. For example if we want to use a text field to insert an email address, we could use the built-in validator EmailAddressValidator to ensure that the inserted input will respect the email format local-part@domain : TextField email = new TextField("email"); email.add(EmailAddressValidator.getInstance()); 73 Wicket comes with a set of built-in validators that should suit most of our needs. We will see them later in this chapter. Feedback messages and localization Wicket generates a feedback message for each field that doesn't satisfy one of its validation rules. For example the message generated when a required field is left empty is the following Field '