Chapter 5. The Wicket Factor

Table of Contents

5.1. Getting Started
5.2. Listing Issues
5.3. Editing Projects
5.4. Enhancing The Application
5.4.1. Entity Drop Downs
5.4.2. Selecting Projects
5.5. Summing Up Wicket
5.5.1. Choosing Between Them

After completing this set of articles, I decided to take a look at this same project and try and implement it with a framework that didn't provide conversational and flow functionality. Rather than start from scratch with something like PHP or Spring MVC which would make the statefulness completely manual, I decided to try and write it in Apache Wicket which is another framework I'm a fan of. Wicket is a framework which totally abstracts the HTTP and web mechanisms allowing the developer to write their application using pure java and Object Oriented code, more like a Swing Application.

This isn't meant to be a strict head to head against Seam and Spring for a number of reasons. First, Seam and SWF both offer built-in functionality to solve the problems we are trying to work around. Wicket just gives you the environment to build your own solutions to those problems. The value-add from Wicket is that it stays out of your way and only acts as a very thin layer between your OO Java code and the server. Because Seam and Spring Web Flow were supposed to handle the issues of creating stateful web applications, I had a 'rule' that the applications should be mainly built using the features out of the box rather than those which were created from code. With Wicket, just about every page you write involves writing some code so that rule doesn't quite apply.

If there is any comparison it would be how easy it is to implement similar functionality using Wicket. Granted, there is a lot of code in Seam and SWF that does a lot of work, however I think it quite likely that implementing lightweight alternatives to some of the most used core functionalities of these frameworks is possible with Wicket.

5.1. Getting Started

Creating an application with Wicket is simple, simpler than the other two frameworks especially if you are using Maven. The Wicket web site also includes instructions on starting a Wicket project with Maven. To set up the application in Eclipse, just create a new web application, and create a subclass of a wicket WebApplication . The only requirement here is that you implement the getHomePage method that returns the default page class. Only a minimal amount of xml needs to be added to web.xml to add the Wicket servlet and give the class name of the Web Application class. There is no other XML configuration required for Wicket.

Example 5.1.  WicketTrackerApplication.java

					
	public class WicketTrackerApplication extends WebApplication {
		@Override
		public Class getHomePage() {
			return ProjectListPage.class;		//we'll define this later
		}		
	}
				

Example 5.2.  Web.xml

					
	<filter>
		<filter-name>WicketTrackerApp</filter-name>
		<filter-class>
			org.apache.wicket.protocol.http.WicketFilter
		</filter-class>
		<init-param>
			<param-name>applicationClassName</param-name>
			<param-value>
				org.wicketracker.web.WicketTrackerApplication
			</param-value>
		</init-param>
	</filter>
	<filter-mapping>
		<filter-name>WicketTrackerApp</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>

				

Wicket pages work by defining a page class and some HTML with the same file name for each page in the application. The HTML and the class reside in the same source package, but Wicket can be configured to keep the HTML in another location. In a Wicket page, the HTML contains the markup and in the corresponding class, you create java-side components to be bound to the markup. The concept is easy to understand once you see an example. We'll start with our project view page which consists of the ProjectViewPage.java class and the markup ProjectViewPage.html . I've also created a simple template called BasePage which also consists of some HTML and a class from which our pages will extend. This is markup inheritance and is how Wicket handles templating.

Example 5.3.  ProjectViewPage.html interface

					
<html>
<body>
<wicket:extend>
	<table>
		<tr>
			<td class="label">ID</td>
			<td><span wicket:id="id">{id}</span></td>
		</tr>

		<tr>
			<td class="label">Title</td>
			<td><span wicket:id="title">{title}</span></td>
		</tr>
	</table>
</wicket:extend>
</body>
</html>
				

I used a table for the layout simply because I didn't want to clutter the HTML with additional markup to make things lay out nicely. Here we have the Id and Title captions created as spans that contain wicket:id attributes. These attributes provide a way to bind the markup to the server side components we will create in our backing java code.

Example 5.4.  ProjectViewPage.java class

					
public class ProjectViewPage extends BasePage {

	public ProjectViewPage(PageParameters parameters) {
		Long  id = ParamUtils.getLongObject(parameters, "projectId");
		Project project = EMF.createEntityManager().find(Project.class, id);
		add(new Label("id",project.getId().toString()));
		add(new Label("title",project.getTitle()));				
	}	
}

				

In the Java class for the project view page, we get the projectId from the page parameters, load the project and then create the Wicket label components using the project object to provide values for the components.

We can create a similar page with the same kind of code for the Issue object which we will call IssueViewPage . When we get to them, the edit pages for the project and issues will be somewhat similar which makes you realize that one key fundamental to developing with Wicket is that you can leverage all the best Java design practices to reduce complexity and repetition. For example, the code to grab the Id from the parameters and load the object could be genericized including handling errors for missing parameters or missing entities. When you start using Wicket, you almost get a case of code freeze as you start thinking of the possibilities for creating very re-usable code and mini-frameworks with just a small amount of code. In these examples, I have opted not to go a generic route but have focused on the different ways that Wicket will let you do certain things.

One common feature in Wicket is the concept of models which provides Wicket components with source data for display. Initially, you might find yourself just passing the String values to the component as the model like we did in the projectView page. Models can also be objects that implement the IModel interface. This simple interface provides a mechanism for the component to consume the model as needed from the implementation. The implementation could just hold a simple object reference, or it could trigger the fetching of data from the database or some external source. Again, the abstraction leads to unlimited possibilities.

I implemented the IssueView page a little differently by using a CompoundPropertyModel which can be applied to a parent container such as a page, form or panel and be shared with the child components in that container. The child components take their values from the model using the reflected property values based on the component ids. The CompoundPropertyModel becomes far more useful when we are editing values and it provides the two way binding by reading the values from the model and pushing them back into the model on the update.

Example 5.5.  IssueViewPage.java

						
public class IssueViewPage extends BasePage {
	
	public IssueViewPage(PageParameters parameters) {
		Long  id = ParamUtils.getLongObject(parameters, "issueId");
		initPage(id);		
	}
	
	public void initPage(final Long id) {
				
		Issue issue = EMF.createEntityManager().find(Issue.class, id);
		
		IModel compound = new CompoundPropertyModel(issue);
		setModel(compound);
		
		add(new Label("title"));
		add(new Label("description"));
		add(new Label("id"));
		add(new Label("project.title"));
		add(new Label("status.title"));
	}
}

				

Example 5.6.  IssueViewPage.html

					
<html>
<body>
<wicket:extend>

	<table>
		<tr>
			<td class="label">ID</td>
			<td><span wicket:id="id">{id}</span></td>
		</tr>

		<tr>
			<td class="label">Title</td>
			<td><span wicket:id="title">{title}</span></td>
		</tr>

		<tr>
			<td class="label">Description</td>
			<td><span wicket:id="description">{description}</span></td>
		</tr>
		
		<tr>
			<td class="label">Project</td>
			<td><span wicket:id="project.title">{project}</span></td>
		</tr>
		
		<tr>
			<td class="label">Status</td>
			<td><span wicket:id="status.title">{status}</span></td>
		</tr>
	</table> 
	
</wicket:extend>
</body>
</html>

				

Note that the text in curly braces acts as a simple visual placeholder for the content while we edit the page and serves no purpose. We call our initPage method to setup the page components, and since we are binding the form to a ComponentPropertyModel we need to give the components and the associated markup the same wicket:id attribute as the name of the properties they will be bound to. We also have properties on the entity that are objects (i.e. project and status) so we need to name our wicket components like we would access the property in java or JSF i.e. project.title . We bind our model to the top level page and the child components use that model to obtain the values based on their name. There is a logical process to locating a model for a component which involves seeing if one is attached to the component, and then searching up the component hierarchy until it finds one. In this case, it finds the compound property model and uses its component name to get the actual value. If you aren't a fan of reflection or you have some more complex needs, you can always just push the values into the component like we did for the project view page. Note though that you would also have to handle extracting the values from the components when the page was submitted.

Now lets take a look at the code for the project list page which uses the ProjectListPage.java class and the ProjectListPage.html markup. We want to fetch the list of projects, and then bind them to some table markup in the page. Let's start with the markup since it will help make the page code clearer.

Example 5.7.  ProjectListPage.html

					
<html xmlns="http://www.w3.org/1999/xhtml"
	xmlns:wicket="http://wicket.apache.org/">
<body>
<wicket:extend>
	<table class="dataTable">
		<tr>
			<th>ID</th>
			<th>Title</th>
			<th>Link</th>
		</tr>
		<tr wicket:id="listView">
			<td><span wicket:id="id">[ID]</span></td>
			<td><span wicket:id="title">[Title]</span></td>
			<td><a href="#" wicket:id="viewLink">view</a></td>
		</tr>
	</table>

</wicket:extend>

</body>
</html>

				

This is the markup for the project view page. It contains a HTML table with a header row, a row with a listView wicket id on it, and some columns. The columns contain either spans or a link with a wicket id in it. Now let us look at the page code for the project listing page.

Example 5.8.  ProjectListPage.java

					
public class ProjectListPage extends BasePage {	

	public ProjectListPage() {
		super();
		initPage();
	}

	public void initPage() {
	
		LoadableDetachableModel model = new LoadableDetachableModel() {

			@Override
			protected Object load() {
				ProjectDao dao = new ProjectDao();
				dao.setEntityManager(EMF.createEntityManager());
				return dao.listProjects();
			}

		};

		ListView listView = new ListView("listView", model) {

			@Override
			protected void populateItem(ListItem item) {
			
			    //get the project for this row
				Project project = (Project) item.getModelObject();
				
				//add the components for this row
				item.add(new Label("id", project.getId().toString()));
				item.add(new Label("title", project.getTitle()));
				
				//create a link for the project view page
				PageParameters params = new PageParameters();
				params.add("projectId", project.getId().toString());
				item.add(new BookmarkablePageLink("viewLink",
						ProjectViewPage.class, params));
			}
		};

		add(listView);		
	}

}

				

This code has a couple of new things going on. For the model, we used a LoadableDetachableModel which acts as a proxy and only loads the actual data when needed by calling the load method. This data is detached (set to null) when the detach() method is called which means that we only keep our data around as long as we need it and it is not stored with the page object, the Model proxy is stored instead which saves server session space. Once we have our model, we bind it to a ListView component which provides a means of iterating over a collection of items. For each row, the populateItem method is called and components can be added to that row.

We also created our first link in Wicket. I found linking was a little cumbersome at first given that there is now obvious way to do it. In the HTML, we create a link with an empty href attribute and we give it a wicket id. In the java code, we create a link component with the same component Id, a Wicket WebPage class, and we add the optional parameters to pass the projectId for that row. If you execute the application, you will see that the link generated is projects?wicket:bookmarkablePage=:org.wicketracker.web.pages.projects.ProjectViewPage&projectId=3 . Kind of ugly huh? Thankfully, we can beautify it by mounting the page as one that can be bookmarked. In our main Web Application class, we can add the following code to make our URLs more user friendly.

Example 5.9.  WicketTrackerApplication.java

					
public class WicketTrackerApplication extends WebApplication {

	
	@Override
	public Class getHomePage() {
		return ProjectListPage.class;		
	}	
	
	@Override
	protected void init() {
		super.init();						
		mountBookmarkablePage("/projects", ProjectListPage.class);
		mountBookmarkablePage("/projectView", ProjectViewPage.class);		
		mountBookmarkablePage("/issueView", IssueViewPage.class);		
	}	
}					

				

Now when we look at our URLs, we will get something like http://localhost:8080/WicketIssue/projectView/projectId/3/ .

5.2. Listing Issues

Our project view page needs to have a list of the issues for that project which entails grabbing the list of issues for the project and putting them in a table. We will use a Wicket panel which are similar to facelets in that they have markup that can be re-used in several pages. Unlike facelets, there is code associated with the panel as there is with most other Wicket elements. The panel is built the same way pages are, by using markup and then code behind it binding the markup to server side components. One key difference is that typically the model is passed into the panel constructor. Usually the data displayed in a panel depends on the context of the parent page in which it is displayed. Consider a panel to edit an address where the address to be edited depends wholly on the page it is contained in (person address, company address etc). In such cases, the panel itself is not responsible for loading the data, instead it relies on the containing page to pass it the data. Of course, this is not always the case, and the required data may be generated in the panel as the situation demands (i.e. a panel that lets you search for items). In our simple case, we want to pass in a list of Issues as the model into the constructor. However, good design with Wickets flexibility says we can create constructors (or static methods) that take a projectId and create a model for the issues for that project and pass that on to the proper panel constructor. We can also write something similar to promote type safety so this panel is only ever passed a list of Issue objects which are then wrapped in a model instance.

Example 5.10.  IssueListPanel.html

					
<html xmlns="http://www.w3.org/1999/xhtml"
	xmlns:wicket="http://wicket.apache.org/">
<body>
<wicket:panel>

	<table class="dataTable">
	
		<tr>
			<th>ID</th>
			<th>Title</th>
			<th>Status</th>
			<th></th>
		</tr>
		
		<tr wicket:id="issueList">
			<td><span wicket:id="id">[ID]</span></td>
			<td><span wicket:id="title">[Title]</span></td>
			<td><span wicket:id="status">[Status]</span></td>
			<td><a href="#" wicket:id="linkViewIssue">view</a><br/>			
			</td>
		</tr>
		
	</table>

</wicket:panel>
</body>
</html>					


				

Example 5.11.  IssueListPanel.java

					
package org.wicketracker.web.pages.issues;

import org.apache.wicket.PageParameters;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.link.BookmarkablePageLink;
import org.apache.wicket.markup.html.list.ListItem;
import org.apache.wicket.markup.html.list.ListView;
import org.apache.wicket.markup.html.panel.Panel;
import org.apache.wicket.model.IModel;
import org.wicketracker.model.model.Issue;

public class IssueListPanel extends Panel {

	public IssueListPanel(String id, IModel model) {
		super(id, model);
		bindList();
	}

	public void bindList() {
		ListView listView = new ListView("issueList",getModel()) {

			@Override
			protected void populateItem(ListItem item) {
				Issue issue = (Issue) item.getModelObject();
				item.add(new Label("id",issue.getId().toString()));
				item.add(new Label("title",issue.getTitle()));
				item.add(new Label("status",issue.getStatus().getTitle()));
				
				PageParameters params = new PageParameters();
				params.add("issueId", issue.getId().toString());
				item.add(new BookmarkablePageLink("linkViewIssue",IssueViewPage.class,params));				
			}
			
		};
		add(listView);
	}

}					


				

The concept should be fairly simple. The constructor for the Panel takes a model that we then bind to our ListView called issueList . This issueList is referenced in the markup in the table row. In the ListView anonymous class, we implemented the populateItem method to bind the data for that row to the issue object for that row. We don't see any code to actually fetch issues because we expect the parent container to do that for us since all this panel knows is that it expects a list of Issue objects. However, this code doesn't enforce that rule, you could send in a list of any type wrapped in a model and it would accept it. However, Wicket allows you to enforce type safety by creating methods to accept typed parameters.

There is a small gotcha here in that you need to think ahead about the interface to these panels. For example, if the panel relied on a compound property model in the view, is it up to the panel owner (the page) to wrap the data in that model, or should the panel receive the raw objects and then wrap them in a property model? It seems that the best strategy is to use the latter since then the panel gets to create the exact model it needs, and the caller is presented with a type safe interface where it passes in (a list of) typed objects. However, this leads to the problem of scoping the model, since you are passing raw objects, how is the panel to know whether it is detachable, or whether it is to be serialized in the page? To get around this, you could pass in an IModel instance that will be wrapped by the panel in a compound property model, but then we lose type safety. Current versions of Wicket (1.3.6) don't have support for generics which is a shame since genericized models would be a great help in cases like this. Regardless, code needs to be documented to describe how to interface with these components.

This issue list panel can be reused in several places where we could pass in different lists of issues. Here we will use it in the project view page to show the list of issues for the project. To do this, we need to add the panel placeholder to the project view page and add the panel and pass it a model in the page code.

Example 5.12.  Additional markup in ProjectViewPage.html for the issues list panel.

					
<div wicket:id="issues"/>
				

Example 5.13.  Additional code in ProjectViewPage.java for the issues list panel in initPage()

					
IModel issuesModel = new LoadableDetachableModel() {

    @Override
	protected Object load() {
	    ProjectDao dao = new ProjectDao();
	    dao.setEntityManager(EMF.createEntityManager());
	    return dao.findIssuesForProject(id);
	}			
};
add(new IssueListPanel("issues",issuesModel));



				

That's it, pretty simple. This code also handles the issue of state management so the list is not saved with the page since we are using a detachable model.

5.3. Editing Projects

To edit a project, we go through the same steps as before creating an HTML page and a java class with the same name, and putting our markup in the HTML file and binding it to components in the java class. This time, we will be creating text editors and submit button components. In this section, we will use a Form component to handle the form submission. We will create an inner class to define the form which will contain the edit controls and handle the submission. In the form submission, we will save the updates to the Project instance.

Example 5.14.  ProjectEditPage.html

					
<html>
<body>
<wicket:extend>
	<form wicket:id="form">
	<table>
		<tr>
			<td class="label">ID</td>
			<td><span wicket:id="id">{id}</span></td>
		</tr>

		<tr>
			<td class="label">Title</td>
			<td><input wicket:id="title" /></td>
		</tr>
	</table>
	<input type="submit" value="Save" wicket:id="saveButton"/>
	<input type="submit" value="Cancel" wicket:id="cancelButton"/>
	</form>
	
</wicket:extend>
</body>
</html>					


				

Example 5.15.  ProjectEditPage.java

					
public class ProjectEditPage extends BasePage {

	private final Long id;
	private final EntityManager entityManager;
	private final Project project;

	public ProjectEditPage(PageParameters parameters) {
		id = ParamUtils.getLongObject(parameters, "projectId");
		entityManager = EMF.createEntityManager();
		if (id == null) {
			project = new Project();
		} else {
			project = entityManager.find(Project.class, id);
		}		
		initPage();
	}

	public void initPage() {
		IModel propModel = new CompoundPropertyModel(project);
		add(new ProjectEditForm("form", propModel));

	}
}
				

We are keeping hold of the instance of the Project object and the EntityManager instance in the page object. This makes it easier to handle persisting the entity back to the same entity manager without attachment issues. This is a questionable practice since this page will probably be serialized and it would include the entity manager which may or may not be serializable. There may also be issues in a replicated environment where replicating the entity manager may have unintended consequences. We use a CompoundPropertyModel assigned to the form to set the values of the individual editors (Id and Title). The form component is set up server side using an inner class called ProjectEditForm .

Example 5.16.  ProjectEditForm inner class in the ProjectEditPage class.

					
	class ProjectEditForm extends Form {

		public ProjectEditForm(String id, IModel model) {
			super(id, model);
			add(new Label("id"));
			add(new TextField("title"));
			Button saveButton = new Button("saveButton");
			Button cancelButton = new Button("cancelButton") {
				@Override
				public void onSubmit() {
					setResponsePage(ProjectListPage.class);
				}
			};
			cancelButton.setDefaultFormProcessing(false);

			add(cancelButton);
			add(saveButton);

		}
					
		@Override
		protected void onSubmit() {
			super.onSubmit();
			
			//get the project from the model
			Project project = (Project) getModelObject();
			ProjectDao dao = new ProjectDao();			
			dao.setEntityManager(entityManager);
			dao.saveProject(project);
								
			//redirect to the project view page
			PageParameters params = new PageParameters();
			params.add("projectId", project.getId().toString());
			setResponsePage(ProjectViewPage.class, params);
		}
	}

				

Another way we could have done this is by not using an inner class and reproducing this code in the main page class, and adding the components to a Form instance we created. We can demonstrate this in the IssueEditPage.java class.

For the issue edit page, our markup is pretty much the same as you would expect, text editors placed inside a form with a save and cancel button. The HTML hierarchy follows the same structure as the correlating components in the java class. The page at the top with a child form, and the id, title etc.. as child components.

Example 5.17.  IssueEditPage.html

					
<html xmlns="http://www.w3.org/1999/xhtml"
	xmlns:wicket="http://wicket.apache.org/">
<body>
<wicket:extend>
	<form wicket:id="form">
	<table>
		<tr>
			<td class="label">ID</td>
			<td><span wicket:id="id">{id}</span></td>
		</tr>

		<tr>
			<td class="label">Title</td>
			<td><input wicket:id="title" value="{title}" /></td>
		</tr>

		<tr>
			<td class="label">Description</td>
			<td><input wicket:id="description" value="{description}" /></td>
		</tr>

		<tr>
			<td class="label">Project</td>
			<td><span wicket:id="project.title">Project.title</span></td>
		</tr>

		<tr>
			<td class="label">Status</td>
			<td><input wicket:id="status.title" value="{status}" /></td>
		</tr>
	</table>
	<input type="submit" value="Save" wicket:id="saveButton" /> 
	<input type="submit" value="Cancel" wicket:id="cancelButton" /> 
	<a href="projects">Back To Projects</a>
	</form>
</wicket:extend>
</body>
</html>					


				

For now, I am leaving the project and status drop down selections as text fields. We'll look at turning them into drop down boxes later. Here we are creating the form and attaching the child components within our page instance as opposed to using an inner class.

Example 5.18.  IssueEditPage.java

					
public class IssueEditPage extends BasePage {

	private static final Logger log = Logger.getLogger(IssueEditPage.class);
	private final Long id;
	private final Long projectId;
	private final EntityManager entityManager;
	private Issue issue;	

	public IssueEditPage(PageParameters parameters) {
	    
		id = ParamUtils.getLongObject(parameters, "issueId");
		projectId = ParamUtils.getLongObject(parameters, "projectId");
		entityManager = EMF.createEntityManager();
		initPage();
	}

	public void initPage() {
	    //we check to see if an id was passed and if not,
	    //we create a new Issue object if there is a project Id available
	    //If there is no project or Issue Id, then we go back to the project List 
	    //We can also add security logic here to see if they can edit/add Issues.
		if (id == null) {
			if (projectId == null) {
				getSession().error("You cannot create an issue without a project Id");
				setResponsePage(ProjectListPage.class);
				return;
			}			
			// create new issue
			issue = new Issue();
			Project project = entityManager.find(Project.class, projectId);
			if (project == null) {
				getSession().error("Project Not Found");
				setResponsePage(ProjectListPage.class);			
				return;	
			}
			issue.setProject(project);
		} else {
		    //load the issue
			issue = entityManager.find(Issue.class, id);
			if (issue == null) {
				getSession().error("Issue Not Found");
				setResponsePage(ProjectListPage.class);
				return;
			}
		}		
		
		//create the model around the issue object
		IModel model = new CompoundPropertyModel(issue);
		
		//create our form instance		
		Form form = new Form("form",model) {
			@Override
			protected void onSubmit() {
				IssueDao dao = new IssueDao();
				dao.setEntityManager(entityManager);
				dao.save(issue);
				setResponsePage(IssueViewPage.class,new PageParameters("issueId="+issue.getId().toString()));
			}
		};
		
		//add the form components
		form.add(new TextField("title"));
		form.add(new TextField("description"));
		form.add(new Label("id"));
		form.add(new Label("project.title"));
		form.add(new TextField("status.title"));
		
		//create the form buttons
		Button saveButton = new Button("saveButton");
		
		//when cancelling, we check to see if it was a new issue
		//if so, we go to the project page
		//otherwise, we go to the issue view page
		Button cancelButton = new Button("cancelButton") {
			@Override
			public void onSubmit() {			
				super.onSubmit();
				PageParameters params = new PageParameters();
				
				
				if (issue.getId() == null) {
					//goto project view since this issue doesn't exist
					params.add("projectId", projectId.toString());	
					setResponsePage(ProjectViewPage.class,params);
				} else {
					//goto issue view page
					params.add("issueId", issue.getId().toString());	
					setResponsePage(IssueViewPage.class,params);					
				}
			}			
		};
		
		//we don't want to handle the submit on clicking the button
		cancelButton.setDefaultFormProcessing(false);
	
	    //add the buttons to the form
		form.add(saveButton);
		form.add(cancelButton);		
		
		//add the form
		add(form);
	}
}					

				

That's a lot of code, but it actually does quite a bit. We perform some real-world validation on the input parameters and if it fails we immediately jump to another page and pass an error message. If the user cancels the editing, we jump to either the issue view page if this was an existing Issue, or to the project page if this was a new issue (and therefore there is nothing to view). Compared to the XML based navigation of JSF this appears nice and tidy as well as being flexible enough to handle complex cases with java code. Furthermore, we didn't have to jump to different files to handle the different pieces of the process. If we get to a point where a page needs multiple navigation rules depending on how it is used, we can implement some additional code later, even in a separate class if needs be and refactor our existing code. Also, rather than create a new inner class, we created our own Form instance, bound it to the model and added components to it in the page itself. The defaultFormProcessing on the button is similar to the immediate attribute on JSF buttons. When this is turned off, Wicket skips the conversion, validation and model updating stages of the request process.

5.4. Enhancing The Application

So far, we have handled the basics of a web application. Loading, displaying, editing and saving data. The Seam vs Spring Web Flow articles also tackle more complex issues such as stateful navigation. The main test for this was the ability to edit an object (like the issue), go to another page to select a project and then come back to the issue editor with the original issue changes intact and the new project selected. The goal was to see if the frameworks would provide us with high level functionality without forcing us to develop unscalable and complex low level solutions.

5.4.1. Entity Drop Downs

First though, let's start by creating drop downs from entity objects and bind them to an object property and we'll see if Wicket handles the conversion and update easily and correctly. We'll start with fetching the list of status values in the IssueEditPage .

Example 5.19.  Adding issue status drop downs IssueEditPage.java .

						
public class IssueEditPage extends BasePage {

    ...
    ...
	private final List<IssueStatus> statuses;

	public IssueEditPage(PageParameters parameters) {	
		...
		...		
		//load the list of issue status values
		IssueDao dao = new IssueDao();
		dao.setEntityManager(entityManager);
		statuses = dao.listStatuses();
		
		initPage();
	}
	
	public void initPage() {
		...
		...
		DropDownChoice statusSelect = new DropDownChoice("status",statuses);
		form.add(statusSelect);
		...
		...
	}
					

We removed the original component for status.title and replaced it with the above drop down choice. We also changed the HTML markup to use a select.

Example 5.20.  HTML to use a select instead of text in IssueEditPage.html

						
<select wicket:id="status" value="{status}" />						

					

Because we are using the compound model in the form which references the issue, we need to refer to the status property of the Issue object. This code will give us the ability to show the issue state in a drop down and when we save it, write the value back to the issue's status property because we are using a ComponentPropertyModel .

Figure 5.1. Drop downs using Wicket

Drop downs using Wicket

As you can see, it works, almost. We need to display the correct text in the drop down as we currently display the toString() value. Looking at the options for creating a DropDownChoice , we can also pass in an IChoiceRenderer . We add that as an anonymous class to the constructor. Obviously, the better solution is to creating a class that implements this interface for this type so it can be reused anywhere we need to display the issue status information.

Example 5.21.  Adding the IChoiceRenderer to IssueEditPage.java

						
		DropDownChoice statusSelect = new DropDownChoice("status",statuses,new IChoiceRenderer() {

			public Object getDisplayValue(Object object) {
				return ((IssueStatus)object).getTitle();
			}

			public String getIdValue(Object object, int index) {
				return ((IssueStatus)object).getId().toString();				
			}
			
		});
					

Figure 5.2.  Wicket drop downs with properly titled choices

Wicket drop downs with properly titled choices

That was pretty painless and avoided the problems of having to wrap the objects in a DataModel as JSF does. When we change values, and save the issue, the correct value is put into the status property thanks to the CompoundPropertyModel .

5.4.2. Selecting Projects

Now let's see how we can navigate from the issue edit page, select a project and go back to the issue edit page to resume editing the issue. First let's consider how we do this since we are completely on our own on how we implement it. We want to navigate to the project page and when we select a project, put it into the project property on the issue we are editing and return to the issue edit page. This is all while keeping any changes we made to the issue before we navigated away to the project page and back. Let's look at the project list page first to see how this might be done. We want to add a column containing a select link in the list of projects in the project list page to select that project. In the backing code, we add this link component and give it an on click handler which calls a method to handle the selection. The handleSelect method is empty and will be filled in by the calling page since only that page knows what to do when you select an entity.

Example 5.22.  Adding the select link in the ProjectListPage.java .

							
						
public void initPage() {

	LoadableDetachableModel model = new LoadableDetachableModel() {
		...
	};
	
	ListView listView = new ListView("listView", model) {
		@Override
		protected void populateItem(ListItem item) {
			final Project project = (Project) item.getModelObject();
	
			item.add(new Label("id", project.getId().toString()));
			item.add(new Label("title", project.getTitle()));
			...
			...				
			//Adding the select link here	
			item.add(new Link("select") {
				@Override
				public void onClick() {
					log.debug("Submit clicked on project");
					handleSelect(project);
				}
			});
		}
	};
	add(listView);	
}
					

In our ProjectListPage.html page we add the link into a new column in the table showing the list of projects.

Example 5.23.  ProjectListPage.html

						
	<table class="dataTable">
		<tr>
			<th>ID</th>
			<th>Title</th>
			<th>Link</th>
			<th>Select</th>

		</tr>
		<tr wicket:id="listView">
			<td><span wicket:id="id">[ID]</span></td>
			<td><span wicket:id="title">[Title]</span></td>
			<td>
			    <a href="#" wicket:id="viewLink">view</a> 
			    <a href="#" wicket:id="editLink">edit</a>
			</td>
		    <!-- New Select Link Goes Here -->
		    <td><a href="#" wicket:id="select">Select</a></td>
		</tr> 
	</table>					


					

Going back to our issue editor page, we add a button next to our project display text to invoke the project selection.

Example 5.24.  Adding the project change button to our IssueEditPage.html .

						
		<tr>
			<td class="label">Project</td>
			<td>
			    <span wicket:id="project.title" >{project}</span>
			    <input type="submit" wicket:id="select" value="Change"/>
			</td>
		</tr>
					

We then add the corresponding "Change Project" button component in the IssueEditPage.java code. In the onSubmit() method of the button we set the response to point to an instance of the project list page. We pass an instance that we create here as an anonymous class because we want to override the handleSelect method in the ProjectListPage class to set the project property on the issue entity in this page. After assigning the project, we set the response page to this instance of the IssueEditPage class. This causes us to end up back on the original page that we called the project list page from with our original changes to the issue object. To spice things up a bit I put in some validation so you couldn't select the project with an id of 3 just to see how easy it is to validate that selection and stay on that same page while passing a message back to the user.

Example 5.25.  Adding the project selection button in ProjectEditPage.java .

								
		Button changeProject = new Button("btnSelectProject") {

			@Override
			public void onSubmit() {
				setResponsePage(new ProjectListPage() {
					@Override
					public void handleSelect(Project entity) {
						if (entity.getId() == 3) {
							getSession().error(
									"cannot select project with Id 3");
						} else {
							issue.setProject(entity);
							setResponsePage(ProjectEditPage.this);
						}
					}
				});
			}
		};

		changeProject.setDefaultFormProcessing(false);
		form.add(changeProject);
		add(form);

					

You may have noticed is that the select link is always displayed on the project list. In the Seam and Spring JSF versions, we always hid it if there was no selection possible. The reason I have not done so here is because there are ways to do it by componentizing your table and columns which I didn't get in to here. However, the solution is relatively trivial, but requires replacing the table with a DataTable component and defining your columns in code. The DataTable is part of the wicket extensions.

This solution for handling more complex navigation works, and it works really well. It doesn't involve a mess of HTML or XML, just some Java code. Granted, a rigid implementation like this can soon get complex if you need something more sophisticated, however, Wicket makes it easy to knock up a more generic version in a small amount of time. This mechanism is re-usable, and the project list page knows nothing about the calling page which is how we want it. One subtle gem here is the fact that unlike the managed environments of Seam and Spring, you can just create a new anonymous class and override methods to change functionality. This isn't possible with Seam and Spring because they are managed environments and you never create your own components, therefore such dynamic interactions can be harder to implement leaving you to hard wire the relationships between the issue editor and the project selection.

5.5. Summing Up Wicket

Wicket is a really good framework to use, it lays out a minimalist set of ground rules and gives you a great environment to work in. The first important aspect is the ability for Wicket to hold page state which enables you to hold objects between requests. This is a fundamental piece of both Seam and SWF, but Wicket offers this in a simplified fashion where only the page is held as opposed to whatever conversational objects you invoke as part of the flow, as well as incidental ones created by the framework (just look at the list of objects in a conversion in the seam.debug page).

Wicket HTML markup consists of markers into which Wicket will place the component HTML. This makes editing the view straightfoward and doesn't push too much decision making and certainly no business logic into the view . On the back end, in the page object we add the components, couple them to to models and set property values on the components that alters the final HTML. None of this is controlled from the view HTML, it is all done on the java server side. This server side only approach makes component instantiation easier and more natural but can be verbose. You gain the benefit of IDE features which apply to strongly typed Java code such as static typing, code completion, refactoring as well as renaming. To access components in JSF you define a component in a web page, and it can optionally have a binding to a bean property which will hold the JSF component reference on the server side. Wicket just holds the components as a plain old java variable (pojv?) which is natural and efficient without the need to lookup EL component bindings, but, this comes at the expense of having to explicitly declare each component declaration , creation and binding in code. It has been claimed that you can see Wicket markup by opening up the HTML file which is true but since you should be using templating and probably runtime specific stylesheets (i.e, theming) it would be hard to get a good idea of what the page looks like.

Other frameworks (I'm mostly considering Seam and SWF here) have far more rules to obey and they are somewhat more contextual in that they only apply under certain circumstances. They do deliver far more in terms of features, but following the 80/20 principle, 20% of the features will be used 80% of the time, and simplified versions of that can be written in Wicket. I'm not suggesting that you need to consider implementing Drools or full conversion support in Wicket. You could however code individual pages to share objects across pages and requests which is mostly what conversations are used for. However, Wicket does provide built in support for providing pagination components and handling it on the back end in the model and these do work well.

I found Wicket to be fairly simple to use, and rarely had to go look at any reference documentation once the underlying prinicples were understood. I had a little extra work to look up info related to links, templating and displaying data tables, but beyond that, most things could be found using code completion to give me an idea of what I was looking for.

I have a couple of solid concerns and one 'philosophical' concern which is that Wicket really lets you 'explore the studio space', and some people will take this and build huge monuments to good coding practices and OO design. Other developers will take this and create spaghetti code. Regardless, Wicket gives you free will to do with your code what you will, and when you start using it, you'll start spotting all sorts of places where you can invoke the DRY principle (Don't Repeat Yourself) and reduce code repetition. The inverse is that the project might become a victim of Astronaut Architects or code freeze as you try and define the perfect architecture on top of Wicket. Another aspect of this is that any discussion of best practices for Wicket cannot exclude a discussion of best practices for OO code such as using anonymous versus inner versus top level classes, composition over inheritance, and use of GoF design patterns. This is a huge (endless?) discussion which could detract from actually getting things done. The Seam and SWF frameworks expect and direct the boilerplate code to be handled a certain way which as long as it works well is a benefit. Yes, I'm saying that too much freedom can be a bad thing.

Another problem is the potential for abusing the session which is a noted concern by critics of Wicket. Common sense should be applied so you don't hold unnecessary data in the page that ends up being serialized in the session. Using detachable models can help by reloading the data each time the page is rendered. However, this same problem will exist in all stateful frameworks, and caution is required by any framework that handles state in the session. There is also some chatter of problems when holding references to other pages and handling circular references to pages upon serialization. Passing page references around may make stateful coding easier, but it seems that it too could come back to haunt you. Seam and SWF store the state in conversations which time out and are destroyed. While this allows any number of conversations, because they are managed, all the pieces of the conversation time out and are destroyed together and it can help control session sizes.

While the current version of Wicket (1.3.6) doesn't use generics, version 1.4 which is now in release candidate 6 at the time of writing does use generics. However, one problem is the incompatibility between applications using Wicket 1.3.x working with Wicket 1.4. On this basis, you would need to think hard on whether to start with the current stable release even if it is incompatible with the next version which is currently only a release candidate.

JSF , Seam and SWF all depend on EL expressions (or variants of) which can get expensive when you have an expression with multiple elements that need evaluating especially since JSF could repeat the evaluation more than once in a page. In Wicket, you are typically binding the actual object to a model which uses reflection on the object to obtain property values for reading and writing. This is far more efficient since it doesn't have to repeatedly lookup the initial object in a massive dictionary of available objects several times a page.

Wicket appears to be much faster than the JSF based frameworks. No doubt this is partly because of the expense of JSF and EL as well as the bundling of all the other features in the frameworks. Another 'feature' if you want to see it that way is that it can be used with Google App Engine for Java unlike JSF (and therefore Seam and Spring Faces). Web Beans also comes with an example that uses Wicket and GAE, or you can also use Spring with GAE.

Wicket does lack some of the functionality and flexibility of Seam and SWF . Seam offers JSF based email and pdf and excel documents from JSF documents by using the already defined data components letting you do more with what you have already built. Both SWF and Seam come with Dependency Injection capabilities whereas Wicket does not although there are add-ons for Spring, Google Guice, injecting EJBs and even Web Beans. Wicket has a disconnect with injection frameworks since it is an unmanaged and (semi-?)stateful framework. The fact that page instances can be serialized means we need special handling for references to managed beans so we don't serialize and replicate them. However, there is a very capable work around with the spring annotations extensions. Wicket also comes AJAX ready with some easy to use AJAX controls and an AJAX debugger so you can see what messages are going on behind the scenes (a very nice idea).

One important note is that by using POJOs in an unmanaged environment we can very easily subclass web pages or create anonymous class instances with different handlers for different events. We can't just create a new anonymous Spring Bean or Seam component out of thin air and augment it with new features. This is a huge plus for Wicket since this flexibility lets you extend classes in ways such that the base class remains ignorant of the context it is being used. For example, a search and select popup panel should know nothing about the recipient of the selection (the parent page). To get such features in Seam or Spring, you need to rely on the workflow engine to act as the middle man between the different pieces.

Overall, Wicket is a great framework to use, and I hope it really receives the success it deserves as a great lightweight component framework.

5.5.1. Choosing Between Them

As I was thinking about this, I started comparing the frameworks in terms of different languages :

  • Wicket = Assembler - Small, powerful, but has lengthy code that quickly gets messy if you aren't able to organize OO code well. Little stands between you and the bare metal and this gives you a lot of control. To get more complex things done, you need to build on top of it to create a more advanced framework.

  • Spring Web Flow = C++ - It's fast, it's popular, (Spring at least is already in widespread use), but some pieces don't fit well with others at times. A robust but no frills development experience.

  • Seam = Delphi - Almost as capable as C++, and covers a broader range of problems well. It's not as popular, but very easy to use with excellent tooling and all round integration. Solves a number of problems inherent in the other solutions. Mildly slower than C++ (at least early on,not so much later).

They all have different appeals and benefits from different perspectives. If you are looking at frameworks in terms of career, looking at job listings, JSF is leading most web frameworks aside from Struts. Seam may be slow in picking up momentum, but it is ahead of Wicket and SWF. SWF is helped by massive Spring adoption while Seam is almost alien to existing EJB or POJO based applications. As far as popularity goes, Spring Faces is probably the better option with the JSF/Spring/Spring Web Flow combination looking good on a resume. This is interesting, because while I think this is a great option, it has a couple of fairly deep flaws that the others don't which would put them ahead of SWF.

If I were looking at it from the perspective of a single person startup for a small project (which I'm also considering), then this introduces a few more issues. If you want to keep hosting cheap, perhaps even running on something like Google App Engine, then JSF is problematic as not only does 1.2 not run on GAE, but it would probably chew up more resources (on any host) than you would like. For me, Wicket would be the choice there as it is more lightweight and session size is less of a concern given that you have a little more control. Obviously, depending on your needs, Wicket could be a winner in larger projects and isn't limited to smaller projects. With a larger team and a more complex project, more groundwork is needed to standardize the coding practices so you don't have one too many differing coding styles. JSF and Seam/SWF pretty much direct you down that path with one most obvious way of doing most things. Wicket is also useful where alternatives might be overkill such as a shopping cart type app with little state management and user CRUD operations. I really like the Wicket programming model, I just don't think it is applicable in all cases (just like assembly language isn't).

Lastly, I think Seam leads in terms of features and productivity in a cohesive package. I can start a new project and easily code CRUD pages in a matter of minutes with just a few lines of code (mostly XHTML). I can then extend that to provide emails, pdfs and excel spreadsheets, ajax, Seam remoting, and web services using the same backing beans. I don't have to worry about state management, OSiV, Lazy Initializations, I can introduce workflow any time I want and I don't have to worry about pages where I don't want to use workflow and having to come up with an alternate method of getting to my data. This is all wrapped up in a nice cool IDE that is so good I use it with Wicket and Spring Web Flow development. While it has a number of blemishes, most of them can be worked around, and while it has a steeper learning curve, it's not impossible to learn, and once you get it, the productivity can be quite a pay off. Interestingly enough, I have trained people to use Seam whom I cannot imagine would be as quick to pick up the nuances of good OO design in order to work with Wicket.

Lastly, I think it will be interesting to see how the choice of stateful and semi-stateful web frameworks will grow. There is a beta version of Conversations for Tapestry , and Web Beans (JSR 299) will provide a common framework for handling conversation scoped beans as well as a standard for (conversational) dependency injection. It will be interesting to see what new solutions arise from these and how they differ and improve on these pioneering stateful frameworks.


http://www.andygibson.net/