Wicket Application Development

i

started 6-June-2011

Wicket Application Development

Copyright © 2010 H. Turgut Uyar <uyar@itu.edu.tr>

This tutorial is released under the Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License. You are free: • to Share — to copy, distribute and transmit the work • to Remix — to adapt the work Under the following conditions: • Attribution — You must attribute the work in the manner specified by the author or licensor (but not in any way that suggests that they endorse you or your use of the work). • Noncommercial — You may not use this work for commercial purposes. • Share Alike — If you alter, transform, or build upon this work, you may distribute the resulting work only under the same or similar license to this one. You can find more information on the page: http://creativecommons.org/licenses/by-nc-sa/3.0/.

Wicket Application Development
iii

Contents

1

Basics 1.1 1.2 1.3 1.4 Creating the Project . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Dynamic Content . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Adding Links . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Shorter Code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

1 1 5 7 10 13 13 15 19 19 20 23 27 28 31 37 38 39 45 45 46 49

2

Application Structure 2.1 2.2 Adding Stylesheets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Shared Components . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

3

Data Model 3.1 3.2 3.3 Movies . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Displaying Lists . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Movie Collections . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

4

Forms 4.1 4.2 Text Boxes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Check Boxes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

5

Data Persistence 5.1 5.2 A Collection Interface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . JDBC . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

A Development Environment A.1 Installing NetBeans . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . A.2 Installing the Wicket Plugin B Solutions to Exercises . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

.

Screenshot: NetBeans new Wicket project default files .6 1. . . .1 1. . . . . . . . . . . . 2. . . . . . . . . . . . .7 2. . .10 Listing: Home page class providing the current date and time . . . . . . . . . . . . . . . . . .9 Screenshot: Home page containing style sheet and navigation panel . . . . . . . . . . . . . . . . . . 1. . 1. . . . . . . . . . . . . . . . .11 Listing: Initial movie list page template . . .5 2. . . . . . . .1 2. . . . . Listing: Base page class with style sheet component .10 Listing: Base page class constructor with navigation panel . . . . . . . . . . . . . . .4 2. . . . . . . . . . . . . . . . . . . . . . . . . . . .4 1. . . . . . . . . . . . . . . . . . Screenshot: NetBeans new project framework form . . 1. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .2 2. . . . . . . . . . . Listing: Initial home page template . . . . . . . . . . . . . . . . . . . . . . 1. Listing: Home page template with navigation panel . . .8 2. .6 2. . . . . . Listing: Home page template with style sheet . . . . . Screenshot: NetBeans new project name form . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Listing: Navigation panel class . Listing: Home page class extending the base page class . . . . . . . . . . . . . . . . . . . . . . . . . . . . Screenshot: NetBeans new project server form . . . Screenshot: NetBeans new project category form . . . . . . . . . . . . . . . . . . . . . 1 2 2 2 3 4 5 5 6 6 8 8 9 10 10 11 13 14 14 15 15 16 16 17 17 18 18 1. . . . . . .12 Listing: Initial movie list page class . . Listing: Navigation panel template . . . . . . . . . . . . . . . . . . . . . . . . .16 Listing: Home page class constructor using shorter code . 2. . . . . .13 Listing: Home page template with link to movie list page . . . . . . . . . . . . . . . . . . . .2 1. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2. . . . . . . . . . . . . . . . . . . . . . .5 1. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Listing: Initial home page class . . . . . . . . . . . . . . . . . . . 1.15 Listing: Home page class constructor with link component to movie list page . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .3 2. . . . .Wicket Application Development v List of Figures 1. . . . . . . . . . . . . . . . . . . . . . . . . . . 1. . . . . . . . . . . . . . . . . . . . . . . . . . . . Listing: Home page template showing the current date and time . . . . . . . . . .11 Listing: Home page class with navigation panel . . . . . . . . . .9 Screenshot: Home page containing a title and a link to the movie list page . . . . . . .7 1. . . . . . . . . . . . . . . . . . . . . . .14 Listing: Movie list page link class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .8 1. . . . . . . . . . Listing: Home page class constructor with style sheet component . . . . . . . . Listing: Application style sheet . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .3 1. . . . . .

. . . Listing: Header panel class constructor with link component to movie adding page . . . . . . . . . . . . . . . . . . . .9 Screenshot: Creating a folder for external libraries in Netbeans . . . . . .1 Screenshot: NetBeans install welcome page . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .5 5.2 Screenshot: NetBeans install option customization form . . . . . . . . . Listing: Header panel template with link to movie adding page . . . . . . . . . . . . . . . . . . . . . . . . . . Listing: Movie list form class . . . . . . . . . . .10 Screenshot: Movie list page with links to movie display pages . . . . . . . . . . . . . . . . . . . . . . . Listing: Movie collection interface. . . . . . . . . . . . . . . . . . . .5 3. . .2 4. . . . . . . . Listing: Property list view component for movie list . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Listing: Application class containing the collection object . . . .10 Listing: Updating a movie in a collection using JDBC . . . . . . . . . . . . . . . . . . . . . Listing: Movie list page class constructor getting movie list from application . . . . . .10 Listing: Movie list page class containing movie list form component . .6 3. . . . . . . . . . . . Listing: Movie collection class using a database . . . . . . . . . . . . . . . .9 Screenshot: Movie list page populated with test data . . . . Listing: Deleting a movie from a collection using JDBC . . .5 4. .3 Screenshot: NetBeans Wicket plugin installation . . . . . . . . . . . . . .1 5. . . . . . . . . . . . . .3 4. . . . . . . . . . . . . . . . . . . . . . . . .8 5. . . . . . .2 3. . . . . . . . . . . . . . . .7 3. . . .3. . . . . . . . . . . . . . . . . . . Listing: Movie edit form class . . . . . . . . . . . . . Listing: Movie collection interface. .3 3. . . . . . . . . . . . . . . . 19 20 21 22 23 23 24 25 25 26 27 28 29 30 30 31 31 32 34 35 38 39 39 40 41 42 43 43 44 44 46 46 47 3. . . . . . . . . . . . . . . . . . 4. . . . . . . . . . . . . . . . . . . . . . . . . . . . . Listing: Movie class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Listing: Movie list template using a list view . . . . . . Listing: Page template for editing a movie . Listing: Movie list page class with sample movie data .4 5. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Screenshot: Movie list page with delete option . . . . . . . . .4 4. . . . . . . . . Screenshot: NetBeans project properties form for external libraries . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5. . . . . . . . . . . . .8 3. . . . . . .6 4. . . . . . . . . . . . . . . . . . . . . . . . . . .1 4. . . . . . . . . . . . . . . . . . . . . . . . . . . Listing: Movie collection class . . . . Listing: Movie class with id attribute . . . . . . . . . . . . . . . . . . . . . . . . . Listing: Movie list template with check boxes for entries . 5. . . . Listing: Adding a movie to a collection using JDBC . . . . . . . . . . . Screenshot: Movie display page . . . . . . . . . . . . . . . . . . . . . . . . . . A. .2 5. . . . . . . . . . . . .1 3. . . . . . . . . . . . . . . . . . . . . . . . . . . .7 5. . . . . . . . . . . . . . . . . . . . . . .9 Screenshot: Movie edit page . . . . . . 4. . . . Listing: Movie edit page class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . A.4 3. . . . . . . . . . . . . . .7 4. . . . . Listing: Getting movies from a collection using JDBC . . A. . . . . . .3 5. . . . . . . . . . . . . . . .6 5. . . . . . .8 4. . . . . . . . . .

org/ Although the application code does not depend on any particular development environment. Thanks. You can find some installation notes about NetBeans in Appendix A. please e-mail them to me. the narration makes use of NetBeans features and it can be easier to use NetBeans when repeating the steps explained in the tutorial. Although I have prepared this tutorial to the best of my understanding on the subject.Wicket Application Development vii Preface This tutorial aims to demonstrate how to build an application using the Apache Wicket web framework. .apache. and improper uses of Java or Wicket features. If you have any corrections or suggestions. You can find more information about the Wicket project on its web site: http://wicket. Warning Please keep in mind that this is not a "best practices" tutorial. omissions. it just tries to make it easier to understand the Wicket framework for a beginner. it may still contain errors.

.

Wicket Application Development 1 / 55 Chapter 1 Basics We will first start by creating a simple home page containing only a page title. Finally. select "Java Web → Web Application" as the project category (Figure 1. choose "File → New Project" from the main menu and fill in the requested information as follows: • First. In the end. • Finally. select "Wicket" as your framework and type itucs. Fortunately. This second page will be populated with the list of movies in later chapters. the home page will look like in Figure 1.moviedb as the main package (Figure 1. we will provide a link from the home page to the movie list page.blg361. . specify the name of the project as MovieDB. we will create a second page also containing only a page title. select "Apache Tomcat" as the server (Figure 1. • Next. • In the third step. Next.1.1 Creating the Project Creating a Wicket project requires several configuration steps. Then we will add the current date and time to this page to show how dynamic elements are handled in Wicket. You can accept the default project location suggested by NetBeans (Figure 1. To start the project. Figure 1. the Wicket plugin for NetBeans can generate and manage these configuration files so that we won’t have to deal with them.4).5).3).2).1: Screenshot: Home page containing a title and a link to the movie list page 1.

4: Screenshot: NetBeans new project server form .2: Screenshot: NetBeans new project category form Figure 1.3: Screenshot: NetBeans new project name form Figure 1.Figure 1.

Of the remaining files.java as given in Figure 1. leave Application. When you run the project after applying these changes. html. Modify the contents of the files HomePage.java. HeaderPanel. HeaderPanel.8. In order to simplify the discussion. All of the files we will edit will go into this package. The "Projects" pane separates the project files into groups such as source packages and configuration files.css. We will only work with the "Source Packages" group which.html and HomePage. contains a package with the name we have specified at project creation. you should see the text "MovieDB Homepage" in your browser. respectively.Wicket Application Development 3 / 55 Figure 1. .java.7 and Figure 1.6).java as it is. and style.5: Screenshot: NetBeans new project framework form The project will be created with some default files for a typical Wicket application (Figure 1. remove the following files from the project: BasePage. as seen in the screenshot.

6: Screenshot: NetBeans new Wicket project default files .07-June-2011 Figure 1.

org"> <head> <meta http-equiv="Content-Type" content="text/html. import org.html. the date and time on line 13 is just a placeholder to be replaced by the data provided by a Wicket component at runtime. The wicket:id attribute indicates that the contents of this div element are dynamic.8: Listing: Initial home page class This initial version of the application consists of only one web page and there is no dynamic content in that page. as in HomePage. .0 Transitional//EN" "http://www.html. we have to write two files for every page in the application: one is an HTML file that contains the template of the page.apache.org/TR/xhtml1/DTD/xhtml1-transitional.java and HomePage.moviedb.apache.WebPage.wicket. and the other is a Java source file containing the components that control the dynamic elements in the template. The lines 12-14 contain the markup that will display the date and time.blg361. The name of the class (and therefore the base name of the Java source file) has to be the same as the base name of the HTML template file.9.Wicket Application Development 5 / 55 1 2 3 4 5 6 7 8 9 10 11 12 <?xml version="1.w3.2 Dynamic Content Let us add the current date and time to the home page. Since.7: Listing: Initial home page template 1 2 3 4 5 6 7 8 9 package itucs. In Wicket. 1.dtd"> <html xmlns:wicket="http://wicket.0" encoding="UTF-8"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1. charset=UTF-8"/> <title>MovieDB</title> </head> <body> <h1>MovieDB Homepage</h1> </body> </html> Figure 1. there is no need for the class to supply any information to the template. in our first example. there is no dynamic element in the template.markup. Therefore. We change the template as in Figure 1. public class HomePage extends WebPage { public HomePage() { } } Figure 1.

markup. font-size: 70%" wicket:id="datetime"> Tue May 25 14:47:56 EEST 2010 </div> </body> </html> Figure 1.util. now. import java. since the data is a simple string.wicket. If you select the Apache Wicket Label component. import org.html.org"> <head> <meta http-equiv="Content-Type" content="text/html. NetBeans will suggest possible imports starting with these letters.1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 <?xml version="1. Label labelDateTime = new Label("datetime". When writing the label construction statement (line 11). import org. In our example.blg361.w3. You can use the NetBeans autocomplete feature to simplify this. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 package itucs.html.10). that means that the HomePage class must contain a Wicket component with the Wicket id datetime. In this case. and the second parameter is the string content of the label. public class HomePage extends WebPage { public HomePage() { Date now = new Date(). type the first few characters of the component (for example. The line 11 shows how to instantite a label component: the first parameter is the Wicket id. Lab) and hit Ctrl-Space.moviedb.Label.apache.wicket.Date. We have to choose a suitable Wicket component that can supply the requested data. the connection between the template element and the label component will be established. we can use the Wicket Label component (Figure 1.apache.10: Listing: Home page class providing the current date and time Tip Note that you have to import the necessary Wicket component class (line 5). NetBeans will autocomplete the text as "Label" and add the import statement to the beginning of the file.markup. When this component is added to the page (line 12).0 Transitional//EN" "http://www.apache.org/TR/xhtml1/DTD/xhtml1-transitional. charset=UTF-8"/> <title>MovieDB</title> </head> <body> <h1>MovieDB Homepage</h1> <div style="text-align: right.dtd"> <html xmlns:wicket="http://wicket. The template element and the component are matched using their Wicket id attributes.9: Listing: Home page template showing the current date and time For every dynamic element in the template.0" encoding="UTF-8"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1. this. .add(labelDateTime). } } Figure 1. there has to be a corresponding component in the Java controller class.toString()).basic.WebPage.

whereas componentY (Wicket id y) is added to componentX. Again. select "New → Wicket Page" from the context menu and enter MovieListPage as the name. it made the label a sub-component of the page. componentX. Note that. will run as follows: • An Application object will be instantiated. Wicket matches the hierarchy of the HTML template to the hierarchy of the Java components. when we added the label component to the page component. consider the template below where the span element is nested inside the div element: <body> <div wicket:id="x"> some text <span wicket:id="y">some other text</span> </div> </body> The corresponding Java page component could contain code like given below. Continuing with the example above. For example. SomeOtherComponent componentY = new SomeOtherComponent("y").html and MovieListPage. All elements which do not have a Wicket id will be displayed as they are.html template will be used to display the page. The contents of the div element with the Wicket id datetime will be replaced by the content of the label component with the same id in the HomePage object.11. 1. will instantiate a Label object with the Wicket id datetime and set the current date and time as its contents. . • A HomePage object will be instantiated. To create this page.12). since there is no dynamic element in this template.blg361. as implemented so far. This. it will be populated in later chapters. right click on the itucs.java. This will create two files as explained before: MovieListPage. This object will set the HomePage class as the entry page of the application. The HTML template also has a hierarchy due to the nesting of the HTML tags. The parent component of any component can be retrieved using its getParent method. the corresponding class is mostly empty (Figure 1. the following code will assign componentX to parent: SomeComponent parent = (SomeComponent) componentY.add(componentX). Modify the template as in Figure 1. • The HomePage.Wicket Application Development 7 / 55 The application.3 Adding Links Now we want to create a second page which will be responsible for listing the movies in the collection. the componentX (Wicket id x) is added to this (the page component). this.getParent().add(componentY). For example.moviedb package in the "Projects" pane. in turn. This label will be added to the page. But at first. Adding a component to another component creates a hierarchy between the two. SomeComponent componentX = new SomeComponent("x"). the page will only contain some static text.

As before.org"> <head> <meta http-equiv="Content-Type" content="text/html.markup.apache.WebPage.apache. charset=UTF-8"/> <title>MovieDB</title> </head> <body> <h2>Movie List</h2> </body> </html> Figure 1.blg361. we modify the template as in Figure 1. the href attribute of the a element is just a placeholder and will be replaced by the value supplied by a Wicket link component.11: Listing: Initial movie list page template 1 2 3 4 5 6 7 8 9 package itucs. In order to achieve this.0 Transitional//EN" "http://www.12: Listing: Initial movie list page class Our next step will be to provide a link from the home page to the movie list page.org/TR/xhtml1/DTD/xhtml1-transitional. The code for adding the link is on line 13.dtd"> <html xmlns:wicket="http://wicket. .13.w3. import org. This line states that the necessary information for the a element will be supplied by a Wicket component with the id list_movies in the HomePage class.html.1 2 3 4 5 6 7 8 9 10 11 12 <?xml version="1.moviedb.0" encoding="UTF-8"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1. public final class MovieListPage extends WebPage { public MovieListPage() { } } Figure 1.wicket.

For the new class. we have to implement a constructor and override the onClick method that specifies what will happen when the link is clicked. To fix this. it will require you to write a constructor for this class. Note that since this is not a Wicket page. charset=UTF-8"/> <title>MovieDB</title> </head> <body> <h1>MovieDB Homepage</h1> <ul> <li><a href="#" wicket:id="list_movies">List movies</a></li> </ul> <div style="text-align: right. right click on the package name. select "New → Java Class" and give it the name MovieListPageLink. The resulting file is given in Figure 1.w3.org"> <head> <meta http-equiv="Content-Type" content="text/html. To fix this. it will complain that it cannot find the symbol for the class Link.org/TR/xhtml1/DTD/xhtml1-transitional. Since there is nothing special to do.13: Listing: Home page template with link to movie list page The Wicket framework provides an abstract Link class which can be extended to create a new link class. To create this class. • And finally. Tip When you add the superclass declaration to the class to make the line read public class MovieListPageLink extends Link { you will see a light bulb in the line number column next to this line indicating that there are some problems: • First. it does not need a template associated with it. again click on the light bulb and choose the suggestion to implement all abstract methods. click on the light bulb and choose the suggestion to add the import for the Wicket Link class. • Next.apache. Constructor methods of Wicket component classes take an id value as their first parameter (their Wicket id).14.Wicket Application Development 9 / 55 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 <?xml version="1. the constructor will just invoke the constructor of its superclass with the same parameter (line 8). The onClick method creates a new instance of a movie list page (line 13) and calls the setResponsePage method to direct the user to this newly created page (line 14). .0 Transitional//EN" "http://www.dtd"> <html xmlns:wicket="http://wicket. font-size: 70%" wicket:id="datetime"> Tue May 25 14:47:56 EEST 2010 </div> </body> </html> Figure 1.0" encoding="UTF-8"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1. it will say that you have to override the onClick method.

we can change the lines 5-7 of Figure 1.1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 package itucs. this. we do not have to assign the result of every intermediate step to a variable.add(movieListLink). } } Figure 1.wicket.toString())).markup. import org.toString()). Label labelToday = new Label("datetime". now.html. Date now = new Date(). we have to extend the Link class to create a link component for every link with a different target. . For example.blg361. Note that in Figure 1.moviedb. we can use Java anonymous classes to reduce the number of files in our project and make it easier to manage. this. When the project gets larger.14: Listing: Movie list page link class The final step is to add an instance of this link to the constructor of the home page (Figure 1. we can skip the assignment of the label to a variable and send the label directly as parameter to the add method.15).15: Listing: Home page class constructor with link component to movie list page 1. this.Link. That means.16. this. now.add(new Label("datetime". For example. } Figure 1. Instead. 1 2 3 4 5 6 7 8 public HomePage() { MovieListPageLink movieListLink = new MovieListPageLink("list_movies"). when adding the date and time to the home page.add(labelToday).15 as follows: Date now = new Date().apache.link. it becomes impractical to create Java files for every custom Wicket component we need. we extend the Wicket Link class where we instantiate a link to the movie list page and therefore we do not need a MovieListPageLink class anymore.4 Shorter Code There are a few things we can do to make the code shorter. public class MovieListPageLink extends Link { public MovieListPageLink(String id) { super(id).setResponsePage(target). } @Override public void onClick() { MovieListPage target = new MovieListPage(). First of all.

toString())). (p. this. now. } }. Date now = new Date(). 49) . Add a link from the movie list page to the home page.add(new Label("datetime".16: Listing: Home page class constructor using shorter code Exercise.setResponsePage(new MovieListPage()). } Figure 1. this.Wicket Application Development 11 / 55 1 2 3 4 5 6 7 8 9 10 11 12 13 public HomePage() { Link movieListLink = new Link("list_movies") { @Override public void onClick() { this.add(movieListLink).

.

Modify this file as given in Figure 2. See Figure 2. Figure 2. First.2. From that list. select "Web → Cascading Style Sheet" and give it the name style. In this chapter.1: Screenshot: Home page containing style sheet and navigation panel 2.css.1 for the screenshot of the resulting home page. we will add a style sheet to the application. so we will add a style sheet to our package. Right click on the package name in the "Projects" pane and select "New → Other" from the context menu. . This will create a file named style. Then we will create a base page that will contain the components that all pages in the application will acquire.Wicket Application Development 13 / 55 Chapter 2 Application Structure The pages in a web application share some components such as style sheets and global navigation panels.1 Adding Stylesheets We want all our pages to have the same style. we will see how to implement such components without repeating code.

font-family: ’Verdana’. ’Helvetica’.25em. h4 { color: #E9601A. padding: 10px 10px 10px 10px. 1 2 3 4 5 <head> <meta http-equiv="Content-Type" content="text/html. so we add a Wicket StyleSheetReference component in the constructor (Figure 2. } Figure 2. ’Sans-serif’.2: Listing: Application style sheet To add this style sheet to the home page. h3. change the head part of its template as in Figure 2. h2. text-align: left. color: white. font-size: 10pt. ’sans’.3. color: #6F6F6F. } h2 { font-size: 1. } a { color: #6F6F6F. The HomePage class now has to contain a component for this style sheet. } th { background: #C3C3C3.1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 body { background-color: white.3: Listing: Home page template with style sheet . } h1. font-weight: bold. charset=UTF-8"/> <title>MovieDB</title> <link wicket:id="stylesheet" rel="stylesheet" type="text/css" href="#"/> </head> Figure 2. margin: 10px 10px 10px 10px.4). text-decoration: underline.

css")). import org.5.wicket. import org.html. Therefore.moviedb.add(movieListLink). } Figure 2. now. } } Figure 2.blg361. "style.WebPage. Add a new Java class named BasePage to your package (careful: a Java class. this.add(new StyleSheetReference("stylesheet". For instance. we can add it to a base page and extend all application pages from this base page.model.markup. there will be no template for this class). BasePage.apache.. public class BasePage extends WebPage { public BasePage() { this(null). The code of the class is given in Figure 2.add(new Label("datetime".StyleSheetReference. "style.apache. } }.class.html. we had to add the style sheet component to every page class.class.4: Listing: Home page class constructor with style sheet component 2. HomePage.apache. using inheritance.resources. import org. Date now = new Date(). we would like to be able to specify these at one point and let pages get them from that single source.6).wicket.css")). in the previous section.markup. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 package itucs. this. this. not a Wicket page.setResponsePage(new MovieListPage()).IModel. } public BasePage(IModel model) { super(model).toString())). Link movieListLink = new Link("list_movies") { @Override public void onClick() { this.add(new StyleSheetReference("stylesheet".5: Listing: Base page class with style sheet component Now the HomePage class will extend this BasePage instead of the generic WebPage (Figure 2.2 Shared Components Adding shared components to multiple pages in an application is a tedious and error-prone approach. .wicket. Instead.Wicket Application Development 15 / 55 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 public HomePage() { this.

We might need links to the home page or movie list page from many pages in the application. now.apache. Date now = new Date(). this. } }. We are only interested in the lines 9-14. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 <?xml version="1.setResponsePage(new MovieListPage()).dtd"> <html xmlns:wicket="http://wicket. Wicket provides panels which let us handle components as a group.add(movieListLink).0 Transitional//EN" "http://www. The template is given in Figure 2. Add a Wicket Panel named HeaderPanel to your package and you will again get an HTML template and a Java source file.w3.toString())).7. this.8) places the link components into this panel component. having a global navigation mechanism where all such links will be available in all pages might be a good idea. So. the part where we describe the content of the panel.6: Listing: Home page class extending the base page class Another improvement concerns the navigation. } } Figure 2.0" encoding="UTF-8"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1. The corresponding Java class (Figure 2.org/TR/xhtml1/DTD/xhtml1-transitional.org"> <head> <title>MovieDB</title> </head> <body> <wicket:panel> <ul> <li><a href="#" wicket:id="home">Home</a></li> <li><a href="#" wicket:id="list_movies">List movies</a></li> </ul> </wicket:panel> </body> </html> Figure 2.1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 public class HomePage extends BasePage { public HomePage() { Link movieListLink = new Link("list_movies") { @Override public void onClick() { this.add(new Label("datetime".7: Listing: Navigation panel template .

blg361. this.add(homeLink). To make this panel available in all pages.Panel. import org.wicket.markup. Link homeLink = new Link("home") { @Override public void onClick() { this. } } Figure 2.setResponsePage(new HomePage()). font-size: 70%" wicket:id="datetime"> Tue May 25 14:47:56 EEST 2010 </div> </body> Figure 2.8: Listing: Navigation panel class Now our actual pages (the home page and the movie list page) will only add this panel component instead of the link components. this.9.moviedb.9: Listing: Home page template with navigation panel .markup.apache.link.html.11). The home page template has to be modified as in Figure 2.wicket. Link movieListLink = new Link("list_movies") { @Override public void onClick() { this. } }.Wicket Application Development 17 / 55 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 package itucs. import org.10). 1 2 3 4 5 6 7 8 9 <body> <div wicket:id="mainNavigation">links to common pages</div> <h1>MovieDB Homepage</h1> <div style="text-align: right.setResponsePage(new MovieListPage()). public class HeaderPanel extends Panel { public HeaderPanel(String id) { super(id).panel. we add it to the base page (Figure 2.Link. The only component left in the home page is the date and time label (Figure 2.apache.add(movieListLink). } }.html.

css")). } } Figure 2.11: Listing: Home page class with navigation panel Exercise. this. "style.10: Listing: Base page class constructor with navigation panel 1 2 3 4 5 6 7 public class HomePage extends BasePage { public HomePage() { Date now = new Date().add(new StyleSheetReference("stylesheet". } Figure 2.class.1 2 3 4 5 6 public BasePage(IModel model) { super(model).toString())). this. now. (p. 50) .add(new HeaderPanel("mainNavigation")). Arrange the MovieListPage class so that it will use the style sheet and the navigation panel.add(new Label("datetime". this. BasePage.

that is.Wicket Application Development 19 / 55 Chapter 3 Data Model In this chapter.1.1: Screenshot: Movie list page populated with test data 3. there is one more constructor which takes the movie title as parameter. along with their getters and setters. it only contains title and year attributes. Figure 3. First we will implement the movie class and fill the movie list page with some in-place generated test data. Apart from the default constructor which takes no parameters. we will create the Java classes in our data model. we implement a plain Java class as in Figure 3. At first. . The resulting movie list page will look like in Figure 3.1 Movies To represent movies in the application. the classes for movies and movie collections. Then we will implement the movie collection class which will hold some application-wide test data.2.

. This code will generate a tr element for each movie in the list. If the Wicket id in the template matches a list view component. note that. These components are associated with Java lists and every element in the Java list is associated with a ListItem component in the list view. } } Figure 3. they will be replaced when the page is actually rendered.title.3. Again.2 Displaying Lists To display a list of movies. } public void setTitle(String aTitle) { this. we have to connect an HTML template element to a Wicket ListView component. "The Matrix" and "1999" are just placeholders.title = aTitle.year. the underlying markup will be generated for each element in the list.1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 package itucs.2: Listing: Movie class 3. } public String getTitle() { return this. public Movie() { } public Movie(String aTitle) { this. } public void setYear(Integer aYear) { this.blg361. private Integer year = null.year = aYear. We change the code for the movie list template as in Figure 3. public class Movie { private String title = null.setTitle(aTitle).moviedb. } public Integer getYear() { return this.

we generate a sample list (lines 12-18). we have to implement the populateItem method which will be executed for every element in the list. we associate it with this list view component and every item (movie) in the list will be associated with the corresponding list item component in this list view. By passing the movies list as the second parameter to the constructor (line 20).Wicket Application Development 21 / 55 1 2 3 4 5 6 7 8 9 10 11 12 13 14 <body> <div wicket:id="mainNavigation">links to common pages</div> <h2>Movie List</h2> <table> <tr wicket:id="movie_list"> <td> <span wicket:id="title">The Matrix</span> (<span wicket:id="year">1999</span>) </td> </tr> </table> </body> Figure 3. Since we don’t have a data source to supply us with the movie information at the moment. The current element will be passed as the item parameter. That means.getModelObject() call on line 24 will give us the reference of the associated movie object. and we can get the Java object associated with this item using its getModelObject method.4). the item. When extending the ListView class. Note the hierarchies in the HTML template and the Java components: • The Wicket id of the tr element matches the Wicket id of the ListView component object.3: Listing: Movie list template using a list view ListView is an abstract class that has to be extended in order to be used (Figure 3. Also note that the text for a label must be a string. so we convert the year of the movie to a string (line 26). Then we use Wicket Label components to display the title and year of the movie on the web page (lines 25-26). . • The Wicket id of either of the span elements matches the Wicket id of one of the Label components.

ListView. we do not supply the contents for the title and year labels (lines 6-7). • The name of the setter method for an attribute has to start with "set". the movie) to the component (the list view item). followed by the name of the attribute with its first letter capitalized. Again.list. movies) { @Override protected void populateItem(ListItem item) { Movie movie = (Movie) item. } }. org.add(movie2).util.apache.html.getTitle())).add(movie1). movies.util. org.markup. this.markup.list.getModelObject().setYear(1980). Movie movie2 = new Movie("Barton Fink").wicket. For instance.markup. if the name of the attribute is "title". movie1. Wicket will look for a method named getTitle and for the id year.moviedb. .List.5). Movie movie1 = new Movie("The Shining").wicket. the name of the getter has to be "isSuccessful".setYear(1991). Since our Movie class already conforms to these rules.1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 package itucs.ListItem.wicket. ListView movieListView = new ListView("movie_list". the method named getYear. item.Label.LinkedList. Also. Wicket can automatically map the model object (in our case.4: Listing: Movie list page class with sample movie data Wicket also supports a simpler way of creating custom list views. movie.add(movieListView). we just have to extend the PropertyListView class instead of the ListView class to use this feature (Figure 3. the name of the setter has to be "setTitle". in this code.html. This method should take the value to be assigned to the attribute as its only parameter and return nothing.html.add(new Label("title". For the Wicket id title. If your code conforms to a few basic Java conventions. the conversion from integer to string for years is handled automatically. if the attribute is a boolean named "successful". movies. public final class MovieListPage extends BasePage { public MovieListPage() { List<Movie> movies = new LinkedList<Movie>(). followed by the name of the attribute with its first letter capitalized. movie. java.getYear(). • Getters for boolean attributes have to be named starting with "is" instead of "get".blg361.apache. if the name of the attribute is "title". This method should take no parameters and return the value of the attribute in a proper format.add(new Label("year". org. the name of the getter has to be "getTitle". Note that. item. } } Figure 3.apache. For instance. movie2.toString())). The rule is that the model object has to define getters and setters for each of its attributes using a standard interface: • The name of the getter method for an attribute has to start with "get".basic. import import import import import java.

we will implement a class that will represent a movie collection.util. the list of movies was generated by the page that lists the movies. item.add(aMovie).6). movies) { @Override protected void populateItem(ListItem item) { item.movies.movies. } public List<Movie> getMovies() { return this. So.LinkedList.List. instantiate it in the constructor (line 10) and . Therefore.add(new Label("title")).moviedb.util.6: Listing: Movie collection class In our earlier example.3 Movie Collections Next.7).movies. Figure 3. } public void addMovie(Movie aMovie) { this. This is obviously not the proper place to generate the collection because there should be one movie collection object which is accessible to all components in the application. import java. the better place to generate it would be in the Application class (Figure 3. we add a collection object member to this class (line 7). } }.Wicket Application Development 23 / 55 1 2 3 4 5 6 7 8 9 PropertyListView movieListView = new PropertyListView("movie_list". } public void deleteMovie(Movie aMovie) { this.5: Listing: Property list view component for movie list 3. public MovieCollection() { this.remove(aMovie). This class will contain a list of movie objects and some methods to interact with that list such as adding or deleting movies and getting a list of all movies (Figure 3. } } Figure 3.movies = new LinkedList<Movie>(). public class MovieCollection { private List<Movie> movies. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 package itucs. import java.blg361.add(new Label("year")).

apache. we provide some sample data (lines 12-17) in order to test our application. Again.protocol.collection = new MovieCollection().setYear(1980). it has to retrieve them from the application.7: Listing: Application class containing the collection object Now that the MovieListPage class does not generate the list of movies. public Application() { this.setYear(1991). } public Class getHomePage() { return HomePage.collection.addMovie(movie1).addMovie(movie2). 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 package itucs. movie1.wicket. movie2.collection. } } Figure 3. this. this.moviedb. We can use the getApplication method of web page classes to get a handle of the application object that contains this web page (note that this is a Wicket application object that we have to cast to our Application class as in line 2).add a getCollection method which will return this collection (lines 24-26). Movie movie2 = new Movie("Barton Fink"). import org. Movie movie1 = new Movie("The Shining"). So the lines 12-18 in Figure 3.blg361.WebApplication.class.4 will be replaced by the lines 2-4 in Figure 3. } public MovieCollection getCollection() { return this.http.collection.8. public class Application extends WebApplication { private MovieCollection collection. .

organize the movie list page so that the entries are links to pages that will display the selected movie (Figure 3. 50) Figure 3.Wicket Application Development 25 / 55 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 public MovieListPage() { Application app = (Application) this.8: Listing: Movie list page class constructor getting movie list from application The "model" is a very important concept in Wicket development but we have discussed it here very very briefly.add(movieListView).getApplication().9: Screenshot: Movie display page .html Exercise. List<Movie> movies = collection.getCollection().getMovies(). Then. MovieCollection collection = app. Add a page that will display a movie (Figure 3.add(new Label("title")). this.9).add(new Label("year")). movies) { @Override protected void populateItem(ListItem item) { item.apache. You are encouraged to read the section titled "Working with Wicket Models" in the Wicket reference guide: https://cwiki. } Figure 3. item. (p.10). } }.org/WICKET/working-with-wicket-models. PropertyListView movieListView = new PropertyListView("movie_list".

Figure 3.10: Screenshot: Movie list page with links to movie display pages .

2. we will implement the parts that will enable us to modify the collection. Both operations require the use of forms containing components such as text boxes and check boxes.1 and Figure 4. The resulting pages are given in Figure 4. This includes the operations to add a new movie and to delete an existing movie.1: Screenshot: Movie edit page .Wicket Application Development 27 / 55 Chapter 4 Forms In this chapter. Figure 4.

3. Add a Wicket page named MovieEditPage to the package and modify its contents as in Figure 4.1 Text Boxes First.Figure 4. both of which will be responsible for handling text boxes (lines 17 and 21). we need a page to edit the data of a movie. And this component has to contain two other components with the Wicket ids title and year. .2: Screenshot: Movie list page with delete option 4. In order to do this. From this template we can see that the corresponding Wicket page class has to contain a component with the Wicket id movie_edit which has to be able to handle forms (line 13). we will add a new page to our application for adding movies.

. the setTitle method will be called using the contents of the text box as parameter. whenever the contents of the text box for the title needs to be determined.4).org"> <head> <meta http-equiv="Content-Type" content="text/html. To achieve this. To control text boxes in the application. the getTitle method will be called for the movie object. We add two such components to the form (lines 15-16) using the Wicket ids specified in the template.Wicket Application Development 29 / 55 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 <?xml version="1.org/TR/xhtml1/DTD/xhtml1-transitional. it will provide the data for any of the components contained in the page.apache. i. we create a Wicket CompoundPropertyModel object from the movie and set it as the model of this form (lines 12-13).dtd"> <html xmlns:wicket="http://wicket. For example.e. charset=UTF-8"/> <title>MovieDB</title> <link wicket:id="stylesheet" rel="stylesheet" type="text/css" href="#"/> </head> <body> <div wicket:id="mainNavigation">links to common pages</div> <form action="#" wicket:id="movie_edit"> <table> <tr> <th>Title:</th> <td><input wicket:id="title" type="text"/></td> </tr> <tr> <th>Year:</th> <td><input wicket:id="year" type="text" size="4"/></td> </tr> </table> <input value="Save" name="save" type="submit"/> </form> </body> </html> Figure 4. the associations between the movie and the components will be handled automatically.w3. The movie object will serve as the model for the component. we use TextField components. This form component will take the movie object it will edit as a parameter to its constructor (line 9). Since we have set a movie object as the model of this form.0" encoding="UTF-8"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1. Add a new Java class with the name MovieEditForm to the package and specify the Wicket Form component as its superclass (Figure 4.0 Transitional//EN" "http://www.3: Listing: Page template for editing a movie Let us start by creating the form element. And when the form is submitted.

TextField.add(new TextField("title")).setModel(model).markup. this.moviedb.moviedb. CompoundPropertyModel model = new CompoundPropertyModel(aMovie).wicket.html.form. } } Figure 4. we get the movie which is the model object of this form (line 21).form.markup. } } Figure 4. aMovie)). we get a handle to the application object (line 22).html. this.apache. import org. collection.5).add(new TextField("year")). this. import org.add(new MovieEditForm("movie_edit". therefore.apache.addMovie(movie). Application app = (Application) this. and redirect the user to the page that will display this movie (line 25).getModelObject(). we get the collection object from the application (line 23).setResponsePage(new MovieDisplayPage(movie)).blg361. public final class MovieEditPage extends BasePage { public MovieEditPage(Movie aMovie) { this.apache.wicket. This page also takes the movie to be edited as a parameter to its constructor (line 5) and passes it to the form component (line 6). Now we have to add this form component to the MovieEditPage class to complete the connection between the template and all the Wicket components (Figure 4. MovieCollection collection = app.Form. For this particular form. this.1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 package itucs. } @Override public void onSubmit() { Movie movie = (Movie) this. import org.wicket.model. We do this by overriding the onSubmit method of the Wicket Form class. another major task is to specify what will happen when the form is submitted.4: Listing: Movie edit form class When implementing a form. public class MovieEditForm extends Form { public MovieEditForm(String id.CompoundPropertyModel. we need to add the movie object to the collection. add the movie to the collection (line 24). 1 2 3 4 5 6 7 8 package itucs. Movie aMovie) { super(id).getCollection().blg361.5: Listing: Movie edit page class To provide a link to this page from other pages we add a list item to the markup of the header panel template (Fig- .getApplication().

Link movieAddLink = new Link("add_movie") { @Override public void onClick() { Movie movie = new Movie(""). Also note that.setResponsePage(new MovieEditPage(movie)).7: Listing: Header panel class constructor with link component to movie adding page 4. Link homeLink = new Link("home") { . this.add(movieListLink).2 Check Boxes Our next step is to delete movies from the collection. 1 2 3 4 5 6 7 8 9 <body> <wicket:panel> <ul> <li><a href="#" wicket:id="home">Home</a></li> <li><a href="#" wicket:id="list_movies">List movies</a></li> <li><a href="#" wicket:id="add_movie">Add movie</a></li> </ul> </wicket:panel> </body> Figure 4. We will change the movie list page so that there will be a check box next to every movie and a delete button at the bottom of the page.6: Listing: Header panel template with link to movie adding page 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 public HeaderPanel(String id) { super(id). } Figure 4. now that we can add movies to the collection. Link movieListLink = new Link("list_movies") { . Note that. we don’t need the sample movie data anymore and we can delete the relevant lines from the constructor of the Application class (Figure 3..6) and a link component to the corresponding Java class (Figure 4.add(movieAddLink). When the delete button is pressed all the checked movies will be deleted.add(homeLink).. this.7 lines 12-17). } }.Wicket Application Development 31 / 55 ure 4. since all Movie class constructors require a title. we instantiate a new movie object and send it to the edit page as parameter (lines 18-19). this. When this link is clicked.. }.. this. an empty string is provided as title.7). }. .

Therefore we move the code generating the movie list view from the MovieListPage class to this class (lines 24-41) and add the list view under the check group (line 42). so its constructor will be as in Figure 4. We use the div element on line 7 to establish this connection. The constructor creates and adds a check box group component (line 20-22) which it associates with this list. We need a movie list form that will include the movie list view. This code contains a new statement for adding a check box to the list item (line 38).3) are as follows: • There is a check box in front of every movie link (line 10). 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 <body> <div wicket:id="mainNavigation">links to common pages</div> <h2>Movie List</h2> <form action="#" wicket:id="movie_list_form"> <div wicket:id="selected_movies"> <table> <tr wicket:id="movie_list"> <td><input type="checkbox" wicket:id="selected"/></td> <td> <a href="#" wicket:id="movie_link"> <span wicket:id="title">The Matrix</span> (<span wicket:id="year">1999</span>) </a> </td> </tr> </table> </div> <input type="submit" value="Delete" name="delete"/> </form> </body> Figure 4. Until now.8.8: Listing: Movie list template with check boxes for entries The movie list view we have used so far is no longer sufficient for handling this template. • We will group check boxes so that we can handle them easier using a CheckGroup component in Wicket. The MovieListPage class now only needs the form component. which is initialized as an empty linked list in the constructor (line 18). all movies associated with the check boxes under this check group will be elements of the list. The implementation is given in Figure 4. Sending the model of the item as a parameter to the constructor of the Check component (via the getModel method) creates the connection between the check box and the check group it is in. This way. The changes from the earlier version (Figure 3. • There is now a button for submitting this form (line 20).9. • Since check boxes need to be part of a form. This component will keep the list of selected movies in the selectedMovies attribute (line 14). the movie list view used to be directly under the movie list page but now it has to be placed under this check group according to the hierarchy in the HTML template. we put all the elements under a form element (line 6).First. .10. we change the template for the movie list page as in Figure 4. These check boxes will be controlled by Wicket Check components in the Java code.

Then we redirect the user to the movie list page (line 52).Wicket Application Development 33 / 55 As before. Since the selectedMovies attribute keeps the list of movies selected for deletion. we override the onSubmit method to determine the action to take when the submit button is clicked. . we iterate over its elements and delete them from the collection (lines 49-51).

} this.Check.list.basic. item. List<Movie> movies = collection.markup.html.PropertyListView.apache.getCollection().LinkedList. public MovieListForm(String id) { super(id). org.getApplication(). import import import import import import import import java.deleteMovie(movie).add(new Label("year")). org. this. } }.selectedMovies) { collection.getModel())).form.markup.apache.blg361. movieLink.markup. Application app = (Application) this.apache. MovieCollection collection = app.getApplication(). } } Figure 4.selectedMovies).markup.apache.9: Listing: Movie list form class .html. org. movie).add(movieLink).Label. this.add(movieCheckGroup). CheckGroup movieCheckGroup = new CheckGroup("selected_movies". PropertyListView movieListView = new PropertyListView("movie_list". movieCheckGroup. } @Override public void onSubmit() { Application app = (Application) this. movieLink.markup. item.add(movieListView).list.add(new Label("title")).selectedMovies = new LinkedList<Movie>().html. item.getCollection(). this. MovieDisplayPageLink movieLink = new MovieDisplayPageLink("movie_link".html.markup. public class MovieListForm extends Form { private List<Movie> selectedMovies. org.util. java.ListItem.html.util.getMovies().CheckGroup.wicket.form. MovieCollection collection = app. movies) { @Override protected void populateItem(ListItem item) { Movie movie = (Movie) item. org.setResponsePage(new MovieListPage()).wicket.add(new Check("selected".wicket.apache.form.Form. for (Movie movie : this.apache.moviedb.getModelObject().1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 package itucs.List. org.wicket.wicket.html.wicket.

52) . After saving the movie should be to updated in the collection (not added a second time). when clicked. this. (p.add(movieListForm).10: Listing: Movie list page class containing movie list form component Exercise. will take the user to the movie edit page. Add a link to the movie display page which. } Figure 4.Wicket Application Development 35 / 55 1 2 3 4 public MovieListPage() { MovieListForm movieListForm = new MovieListForm("movie_list_form").

.

Let us create a folder to hold the JAR files of the external packages we will need in our project.Wicket Application Development 37 / 55 8-June-2011. Go to the "Files" tab next to the "Projects" tab in the left pane. This chapter has nothing to do with Wicket. In the next form. Every time. right click on the toplevel project entry ("MovieDB") and select "New → Other". In this chapter we will see how to store the data in a database. Wednesday Chapter 5 Data Persistence A major problem with the application as implemented so far is that the data the user enters do not persist. In the file type selection form. . it just uses various data persistence methods and assumes that the reader knows about these. select "Other" from the left list and "Folder" from the right list (Figure 5. type "lib" as the folder name. the application starts with an empty collection and added movies are lost when the application is shut down.1).

. The interface has to contain the methods as shown in the Figure 5.Figure 5.moviedb" source package and create a new Java interface with the name "IMovieCollection".blg361. In the "Projects" pane.1: Screenshot: Creating a folder for external libraries in Netbeans 5.2.1 A Collection Interface In order to make it easier to switch between different persistence mechanisms. right click on the "itucs. we will first create a simple interface that all these mechanisms will implement.

public void addMovie(Movie aMovie). we will use SQLite as our database.3: Listing: Movie collection interface. } Figure 5. Also the references to the MovieCollection class in the MovieEditForm and MovieListForm classes have to be changed to the IMovieCollection interface. public Application() { this.class. Download the JDBC driver JAR file for SQLite from the following page and put it in the "lib" directory you have created: .. } public IMovieCollection getCollection() { return this.2: Listing: Movie collection interface.Wicket Application Development 39 / 55 1 2 3 4 5 6 7 8 9 10 public interface IMovieCollection { public List<Movie> getMovies(). public void updateMovie(Movie aMovie). we just have to acknowledge this by changing the class definition: public MovieCollection implements IMovieCollection { .collection. } } Figure 5. That means changing the Application class as in Figure 5. public void deleteMovie(Movie aMovie). The MovieCollection class based on lists already implements this interface. } public Class getHomePage() { return HomePage.3 so that the only place where the actual collection implementation is used will be the constructor of the application object.. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 public class Application extends WebApplication { private IMovieCollection collection.2 JDBC To keep things simple and to avoid database installation or configuration issues. 5.collection = new MovieCollection(). } We also have to change the code pieces that reference the MovieCollection class so that they will use the IMovieCollection interface.

http://www.xerial.org/trac/Xerial/wiki/SQLiteJDBC Right click on your project in the NetBeans "Projects" pane, select "Properties" from the context menu and add the downloaded JAR file to your project using the "Add JAR/Folder" button in the "Libraries" menu (Figure 5.4).

Figure 5.4: Screenshot: NetBeans project properties form for external libraries

Next, create a database with the name "movies.db" in your home directory and create a table in it using the following SQL statement:
CREATE TABLE MOVIE (ID INTEGER PRIMARY KEY, TITLE VARCHAR(80), YEAR INTEGER)

Tip You can use the SQLite Manager add-on for Firefox to manage SQLite databases:

https://addons.mozilla.org/en-US/firefox/addon/5817/

As indicated by the SQL table creation statement above, movie objects now have id attributes. We modify our Movie class (Figure 5.5) to add this attribute (line 3) and its getter and setter methods (lines 9-15).

Wicket Application Development
41 / 55

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18

public class Movie { private Integer id = null; private String title; private Integer year; ... public void setId(Integer anId) { this.id = anId; } public Integer getId() { return this.id; } ... }

Figure 5.5: Listing: Movie class with id attribute

Now we have to implement a MovieCollectionJDBC class (Figure 5.6) which will implement our common collection interface but this time using a database to store the data (line 1-3). The database is assumed to be a file with the name "movies.sqlite" in the user’s home directory (13-16).

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29

public class MovieCollectionJDBC implements IMovieCollection { private Connection db; public MovieCollectionJDBC() { try { Class.forName("org.sqlite.JDBC"); } catch (ClassNotFoundException ex) { throw new UnsupportedOperationException(ex.getMessage()); } try { String homeDir = System.getProperty("user.home"); String dbFileName = homeDir + File.separator + "movies.sqlite"; String jdbcURL = "jdbc:sqlite:" + dbFileName; this.db = DriverManager.getConnection(jdbcURL); } catch (SQLException ex) { throw new UnsupportedOperationException(ex.getMessage()); } } public List<Movie> getMovies() { ... } public void addMovie(Movie aMovie) { ... } public void deleteMovie(Movie aMovie) { ... } public void updateMovie(Movie aMovie) { ... } }

Figure 5.6: Listing: Movie collection class using a database

The methods for getting the movie list, adding a movie, and removing a movie are simple JDBC operations. They are not in the scope of this tutorial. Only note that, in order to simplify the code, the example throws an UnsupportedOperationException whereever it needs to throw an exception. A real-life application should throw more appropriate exceptions.

close(). Statement statement = this.getInt("YEAR"). try { String query = "SELECT ID.next()) { Integer id = result. Movie movie = new Movie(title). ResultSet result = statement.8: Listing: Adding a movie to a collection using JDBC . } Figure 5. movie.prepareStatement(query).close(). YEAR) VALUES(?. Integer year = result. YEAR FROM MOVIE". aMovie. movie.getYear()).getMessage()). statement. } catch (SQLException ex) { throw new UnsupportedOperationException(ex. statement. TITLE. } } Figure 5.getMessage()). PreparedStatement statement = this. } catch (SQLException ex) { throw new UnsupportedOperationException(ex. movies.setId(id). statement.db. String title = result. } return movies. aMovie. ?)".getInt("ID").createStatement().7: Listing: Getting movies from a collection using JDBC 1 2 3 4 5 6 7 8 9 10 11 public void addMovie(Movie aMovie) { try { String query = "INSERT INTO MOVIE(TITLE.Wicket Application Development 43 / 55 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 public List<Movie> getMovies() { List<Movie> movies = new LinkedList<Movie>().executeUpdate().executeQuery(query). statement.setInt(2. while (result.db.setYear(year).add(movie).setString(1. } result.getTitle()).getString("TITLE").

setInt(3. aMovie. statement. } catch (SQLException ex) { throw new UnsupportedOperationException(ex. statement.setInt(2.db.getYear()).prepareStatement(query). statement. } } Figure 5. } } Figure 5. aMovie.9: Listing: Deleting a movie from a collection using JDBC 1 2 3 4 5 6 7 8 9 10 11 12 13 public void updateMovie(Movie aMovie) { try { String query = "UPDATE MOVIE SET TITLE = ?.prepareStatement(query).getMessage()). we just have to change the collection implementation chosen in the Application constructor: public Application() { this.executeUpdate().collection = new MovieCollectionJDBC().executeUpdate(). } catch (SQLException ex) { throw new UnsupportedOperationException(ex.getMessage()).getId()). statement.1 2 3 4 5 6 7 8 9 10 11 public void deleteMovie(Movie aMovie) { try { String query = "DELETE FROM MOVIE WHERE (ID = ?)".getId()).setString(1.close(). statement. YEAR = ? WHERE (ID = ?)". aMovie.db.close(). aMovie.setInt(1. } . statement. statement. PreparedStatement statement = this. statement.10: Listing: Updating a movie in a collection using JDBC After that. PreparedStatement statement = this.getTitle()).

choose a bundle that includes the "Java Web and EE" component.6. Wednesday Appendix A Development Environment I assume that you already have the Java Development Kit (JDK) installed on your computer. Java SE. After starting the installer. This tutorial has been prepared using the Sun JDK version 1. A. Java Web and EE.Wicket Application Development 45 / 55 8-June-2011. The "Java" bundle is sufficient for the purposes of this tutorial. Apache Tomcat. Features on Demand. these are "Java" and "All".8.org/downloads/6.1).0. later versions might or might not support Wicket plugins -or the plugin used in this tutorial. you can find it on the Java web site: http://java.1 Installing NetBeans You can get the NetBeans installer for your operating system from the NetBeans web site: http://netbeans.org/ This tutorial is based on version 6. it is recommended that you customize the options and select only the following components (Figure A.com/. Though you can accept these defaults.8/ On the download page.2): Base IDE.sun. . the welcome page displays the default installation options (Figure A. In case you have problems. you can find this exact version on the page: http://netbeans. At the time of this writing.

we will install the Wicket plugin.2: Screenshot: NetBeans install option customization form A.1: Screenshot: NetBeans install welcome page Figure A. so no separate Wicket installation is necessary. This plugin contains everything required to develop and run Wicket applications.2 Installing the Wicket Plugin To develop Wicket applications in NetBeans. .Figure A.

3: Screenshot: NetBeans Wicket plugin installation . Hit the "Install" button and restart NetBeans.jsp?pluginid=3586 Select "Tools → Plugins" from the NetBeans menu and open the "Downloaded" tab.Wicket Application Development 47 / 55 Download the NetBeans Wicket plugin files at the following site: http://plugins.netbeans. Click the "Add Plugins" button and select the downloaded files (Figure A.org/PluginPortal/faces/PluginDetailPage.3). Figure A.

.

moviedb.org/TR/xhtml1/DTD/xhtml1-transitional. public final class MovieListPage extends WebPage { public MovieListPage() { Link homeLink = new Link("home") { @Override public void onClick() { this.0 Transitional//EN" "http://www.dtd"> <html xmlns:wicket="http://wicket.add(homeLink).Link.wicket.0" encoding="UTF-8"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1. import org.link.Wicket Application Development 49 / 55 Appendix B Solutions to Exercises Chapter: Basics Add a link from the movie list page to the home page.blg361.apache. MovieListPage.markup.apache.html.setResponsePage(new HomePage()). charset=UTF-8"/> <title>MovieDB</title> </head> <body> <h2>Movie List</h2> <ul> <li><a href="#" wicket:id="home">Home</a></li> </ul> </body> </html> MovieListPage. } }. } .apache.wicket.html. import org.w3.html <?xml version="1.markup.WebPage.org"> <head> <meta http-equiv="Content-Type" content="text/html. this.java package itucs.

organize the movie list page so that the entries are links to pages that will display the selected movie.org/TR/xhtml1/DTD/xhtml1-transitional. MovieListPage. charset=UTF-8"/> <title>MovieDB</title> <link wicket:id="stylesheet" rel="stylesheet" type="text/css" href="#"/> </head> <body> <div wicket:id="mainNavigation">links to common pages</div> <h2>Movie List</h2> </body> </html> MovieListPage.dtd"> <html xmlns:wicket="http://wicket.dtd"> <html xmlns:wicket="http://wicket.apache. public final class MovieListPage extends BasePage { public MovieListPage() { } } Chapter: Data Model Add a page that will display a movie.0" encoding="UTF-8"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.moviedb.0 Transitional//EN" "http://www.w3. Then.blg361.org/TR/xhtml1/DTD/xhtml1-transitional. charset=UTF-8"/> <title>MovieDB</title> <link wicket:id="stylesheet" rel="stylesheet" type="text/css" href="#"/> </head> <body> <div wicket:id="mainNavigation">links to common pages</div> <h2 wicket:id="title">The Matrix</h2> <table> <tr> <th>Year:</th> <td wicket:id="year">1999</td> .html <?xml version="1.html <?xml version="1.org"> <head> <meta http-equiv="Content-Type" content="text/html.0 Transitional//EN" "http://www.0" encoding="UTF-8"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.java package itucs. MovieDisplayPage.w3.apache.} Chapter: Application Structure Arrange the MovieListPage class so that it will use the style sheet and the navigation panel.org"> <head> <meta http-equiv="Content-Type" content="text/html.

Wicket Application Development 51 / 55 </tr> </table> </body> </html> MovieDisplayPage.0" encoding="UTF-8"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1. public final class MovieDisplayPage extends BasePage { public MovieDisplayPage(Movie aMovie) { this. this. public MovieDisplayPageLink(String id.org"> <head> <meta http-equiv="Content-Type" content="text/html. aMovie.toString())).dtd"> <html xmlns:wicket="http://wicket.markup.java package itucs.wicket.apache.blg361.java package itucs.link.0 Transitional//EN" "http://www.blg361.html. import org.markup. Movie aMovie) { super(id). this. } @Override public void onClick() { this.Label.moviedb.setResponsePage(new MovieDisplayPage(this.movie = aMovie.Link.org/TR/xhtml1/DTD/xhtml1-transitional. charset=UTF-8"/> <title>MovieDB</title> <link wicket:id="stylesheet" rel="stylesheet" type="text/css" href="#"/> </head> <body> <div wicket:id="mainNavigation">links to common pages</div> <h2>Movie List</h2> <table> .w3.getYear().apache.apache.wicket.getTitle())).movie)).add(new Label("year".html <?xml version="1. import org. aMovie.html.moviedb. } } MovieListPage. } } MovieDisplayPageLink.add(new Label("title". public class MovieDisplayPageLink extends Link { private Movie movie.basic.

PropertyListView.wicket. public class MovieCollection { .util.basic.apache.apache.java package itucs. import import import import java. movie).wicket.markup. org. org. } }. item.getCollection(). movieLink. MovieDisplayPageLink movieLink = new MovieDisplayPageLink("movie_link".add(new Label("year")).getModelObject().markup.List.java package itucs. public final class MovieListPage extends BasePage { public MovieListPage() { Application app = (Application) this. MovieCollection collection = app. movieLink.blg361.html.add(new Label("title")).util.apache. import java. this. PropertyListView movieListView = new PropertyListView("movie_list". After saving the movie should be to updated in the collection (not added a second time). org. } } Chapter: Forms Add a link to the movie display page which. MovieCollection.markup.LinkedList.ListItem.getMovies().wicket.add(movieLink).util. when clicked.blg361.html.List.getApplication().list.add(movieListView).<tr wicket:id="movie_list"> <td> <a href="#" wicket:id="movie_link"> <span wicket:id="title">The Matrix</span> (<span wicket:id="year">1999</span>) </a> </td> </tr> </table> </body> </html> MovieListPage. List<Movie> movies = collection.Label.list. import java.moviedb.html. movies) { @Override protected void populateItem(ListItem item) { Movie movie = (Movie) item.moviedb. will take the user to the movie edit page.

import org.remove(aMovie). } else { collection.newMovie = newMovieFlag.wicket. public MovieCollection() { this. boolean newMovieFlag) { super(id).form.java package itucs.movies. } public List<Movie> getMovies() { return this.wicket. } public void addMovie(Movie aMovie) { this.Wicket Application Development 53 / 55 private List<Movie> movies.apache. MovieCollection collection = app.CompoundPropertyModel.blg361. CompoundPropertyModel model = new CompoundPropertyModel(aMovie). public class MovieEditForm extends Form { private boolean newMovie.html. import org.markup.movies. if (this.TextField.getCollection().newMovie) { collection. public MovieEditForm(String id.add(new TextField("year")).markup.movies = new LinkedList<Movie>(). } . this. Application app = (Application) this.form.apache.updateMovie(movie). } @Override public void onSubmit() { Movie movie = (Movie) this.getModelObject(). this.apache. } public void updateMovie(Movie aMovie) { } } MovieEditForm.add(aMovie).movies.model. Movie aMovie.setModel(model). } public void deleteMovie(Movie aMovie) { this.Form. this. import org.html.add(new TextField("title")).moviedb.wicket. this.getApplication().addMovie(movie).

wicket.apache.add(new MovieEditForm("movie_edit".html <?xml version="1.html.link. } public MovieEditPage(Movie aMovie.dtd"> <html xmlns:wicket="http://wicket. true)).Label. aMovie.blg361.apache. public final class MovieDisplayPage extends BasePage { private Movie movie.blg361. newMovieFlag)). import org.org/TR/xhtml1/DTD/xhtml1-transitional.html.setResponsePage(new MovieDisplayPage(movie)).add(new MovieEditForm("movie_edit".0" encoding="UTF-8"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.moviedb. charset=UTF-8"/> <title>MovieDB</title> <link wicket:id="stylesheet" rel="stylesheet" type="text/css" href="#"/> </head> <body> <div wicket:id="mainNavigation">links to common pages</div> <h2 wicket:id="title">The Matrix</h2> <table> <tr> <th>Year:</th> <td wicket:id="year">1999</td> </tr> </table> <p><a href="#" wicket:id="edit_link">Edit</a></p> </body> </html> MovieDisplayPage. public MovieDisplayPage(Movie aMovie) { .apache.java package itucs. boolean newMovieFlag) { this.w3. aMovie. public final class MovieEditPage extends BasePage { public MovieEditPage(Movie aMovie) { this.Link.markup.basic.wicket. } } MovieDisplayPage. } } MovieEditPage.0 Transitional//EN" "http://www.this. import org.moviedb.org"> <head> <meta http-equiv="Content-Type" content="text/html.markup.java package itucs.

this. this. false)). Link editLink = new Link("edit_link") { @Override public void onClick() { MovieDisplayPage parent = (MovieDisplayPage) this.toString(this.movie.getParent().getYear()))).movie.getTitle())).add(new Label("year". this. } } .movie. } }.add(new Label("title".add(editLink).setResponsePage(new MovieEditPage(parent.Wicket Application Development 55 / 55 this. Integer. this. this.movie = aMovie.