Comparing Web Frameworks: Wicket
Well, I asked him if he was considering Wicket among the list of web frameworks he's evaluating, and since he wasn't, I offered to do an article comparing Wicket. Simon was kind enough to provide me the source code for what he has done so far, so I could base my comparison on that. In particular, I'm using the same domain model that he's using, since that is a part that should remain the same among the differen web frameworks.
Why did I choose to write this article? Two main reasons. One, I get to learn a new web framework, and I've been told several times by various individuals that Wicket is a cool framework. The other reason is that I like to write about Java, although sometimes it doesn' show. I tried to do this article since the end of January after Simon's last post about Struts, and around that time I actually created the example, but the article took a little longer. I used Wicket 1.1.1 for my example, because when I created it, Wicket 1.2 was only available on CVS. Wicket 1.2 is now reaching beta stages, so I'll probably post a follow up later (hopefully) of what has changed for Wicket 1.2.
So, what is Wicket? This is the description from the main site:
Wicket is a Java web application framework that takes simplicity, separation of concerns and ease of development to a whole new level. Wicket pages can be mocked up, previewed and later revised using standard WYSIWYG HTML design tools. Dynamic content processing and form handling is all handled in Java code using a first-class component model backed by POJO data beans that can easily be persisted using your favourite technology.What that basically means is that Wicket separates the front-end visual design (HTML) from the back-end application logic (Java), using components (think Swing JComponents for the web). Instead of being another MVC framework, Wicket is more of an event-driven framework, like a traditional GUI. However, you could look at each 'component' as a tiny MVC with the 'view' part being the html code (but they won't tell it like that). As you will see later, all the application logic falls inside the Java classes, instead of mixing it with the pages, like JSP (true separation of concerns). The Java code is glued to the HTML page by using a special wicket:id attribute that can be assigned to almost any HTML tag, and that tells Wicket where do you want to render a component. Wicket comes with several components like Labels, Links, Lists, etc., which are uniquely defined on a webpage by setting an Id to the component, and the content which is represented by a Model.
OK, so after that brief introduction, it's time to discuss our example. From the requirements post (see above), I am going to need an application that displays 3 pages. One is the Home Page which shows a list of blog entries, another one is the Blog Detail Page that shows each blog entry, and a special Page Not Found page that will be displayed when the user is trying to access an invalid page (an invalid blog entry).
Now, Wicket itself has a couple of requirements, or rather best practices. The main one is that your web application needs to have a class that extends WebApplication. This is where Wicket starts to differentiate itself from other frameworks. Most other web frameworks I've seen are "hooked on XML". To define pages and interactions, you need to write one or more XML files. For Struts you need to at least write a sruts-config.xml, and if you use tiles, you need another one. JSF has faces-config.xml among others. While I don't see anything wrong in using XML, I do think that this approach scatters your logic, and it makes it a little more troublesome to do. If you're using Wicket, there's only one XML you really need to modify, web.xml, and this isn't even a Wicket requirement, but rather a servlet specification requirement (i.e. you can't make a servlet work if you don't define it in the xml).
So, in our example, to define what servlet will handle the application, I have these lines inside web.xml:
<servlet>As you can see, we are defining a servlet, WicketServlet, that has, as one of its initialization parameters, the full classpath of the class that extends WebApplication, which is our main application class BlogApplication. This is what BlogApplication looks like:
<servlet-name>blog</servlet-name>
<servlet-class>wicket.protocol.http.WicketServlet</servlet-class>
<init-param>
<param-name>applicationClassName</param-name>
<param-value>org.javageek.wicket.BlogApplication</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>blog</servlet-name>
<url-pattern>/app/*</url-pattern>
</servlet-mapping>
package org.javageek.wicket;As you can see in the code, all web application settings are set as plain Java code inside the constructor. Most of these settings I used for development, so I'm skipping their meaning. You can learn more by looking at the ApplicationSettings javadoc. The main code we care about is in bold, and it is where we are setting what component is going to respond as the home page (the main page of our application), which is just a reference to the Index class, which is our home page.
import wicket.Application;
import wicket.ApplicationSettings;
import wicket.protocol.http.WebApplication;
import domain.Blog;
import domain.BlogService;
public class BlogApplication extends WebApplication {
private BlogService blogService = new BlogService();
public BlogApplication() {
getPages().setHomePage(Index.class);
ApplicationSettings settings = getSettings();
settings.configure("development");
settings.setStripWicketTags(true);
settings.setDefaultMarkupEncoding("UTF-8");
settings.setStripXmlDeclarationFromOutput(false);
settings.setBufferResponse(false);
settings.setRenderStrategy(ApplicationSettings.REDIRECT_TO_RENDER);
}
public static final BlogApplication instance() {
return (BlogApplication)Application.get();
}
public Blog getBlog() {
return blogService.getBlog();
}
}
Home Page
Any Wicket page component needs to extend WebPage, so all of our pages will be a subclass. But, to make every page look the same, I'm defining an abstract base class that extends WebPage, and every page for my app will extend this class. BasePage is a very basic class that adds common components to the page:
package org.javageek.wicket;This is where the fun starts. As you can see, I just added two Label components, and each one has an id string, and content. Wicket defines a Model for every component, but it also offers convenience methods like the one I used for the labels. Wicket will wrap the string I'm sending as parameter inside a Model object so I don't have to worry for very simple static cases like labels. After the page class is instantiated, the label components will be available inside the HTML for rendering, wherever I use their respective ids.
import domain.Blog;
import wicket.markup.html.WebPage;
import wicket.markup.html.basic.Label;
public abstract class BasePage extends WebPage {
public BasePage() {
Blog blog = getBlog();
add(new Label("blogName", blog.getName()));
add(new Label("blogDescription", blog.getDescription()));
}
public Blog getBlog() {
return BlogApplication.instance().getBlog();
}
}
This is how the BasePage HTML looks like:
<?xml version="1.0" encoding="utf-8"?>I made the BasePage abstract, so you can't set it as a page and instead you need to subclass it. If you look closely at the body, there's a <wicket:child/> tag, that will be replaced with the BasePage subclass' view. Because we will subclass BasePage, this HTML will serve the purpose of a page template.
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:wicket="http://wicket.sourceforge.net/"
xml:lang="en"
lang="en">
<wicket:head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<title wicket:id="pageTitle">[Blog Entry Title]</title>
<link rel="stylesheet" href="screen.css" type="text/css" />
</wicket:head>
<body>
<div id="container">
<h1><span wicket:id="blogName">[Blog Name]</span></h1>
<h2><span wicket:id="blogDescription">[Blog Description]</span></h2>
<wicket:child/>
</div>
</body>
</html>
Wicket works by parsing the HTML and replacing any tag that has the wicket:id attribute with the content from the component's model, based on the id of the component.
Our main page class, Index, subclasses BasePage and it's where all the logic for displaying the list of the 3 most recent blog entries (in reverse date order) resides. For each blog entry we need to display title, excerpt (if present, with a "read more" link) or full body text, and the date it was posted.
The code for Index is:
package org.javageek.wicket;And this is what the whole HTML file for Index looks like:
import java.text.DateFormat;
import java.util.List;
import wicket.PageParameters;
import wicket.markup.html.basic.Label;
import wicket.markup.html.link.BookmarkablePageLink;
import wicket.markup.html.list.ListItem;
import wicket.markup.html.list.ListView;
import wicket.model.IModel;
import wicket.model.LoadableDetachableModel;
import wicket.util.string.Strings;
import domain.BlogEntry;
public class Index extends BasePage {
public Index() {
IModel entriesModel = new LoadableDetachableModel() {
@Override protected Object load() {
return getBlog().getBlogEntries();
}
};
add(new ListView("blogEntries", entriesModel) {
@Override protected IModel getListItemModel(IModel model, int index) {
List entries = (List) model.getObject(this);
BlogEntry current = (BlogEntry) entries.get(index);
return new BlogEntryModel(current);
}
@Override protected void populateItem(ListItem item) {
final BlogEntry entry = (BlogEntry) item.getModelObject();
final String excerpt = entry.getExcerpt();
final boolean hasExcerpt = !Strings.isEmpty(excerpt);
item.add(new Label("entryTitle", entry.getTitle()));
PageParameters params = new PageParameters();
params.put("id", entry.getId());
item.add(new BookmarkablePageLink("viewBlogEntry", ViewBlogEntry.class, params) {
@Override public boolean isVisible() {
return hasExcerpt;
}
});
if (hasExcerpt) {
item.add(new Label("entryBody", entry.getExcerpt()).setEscapeModelStrings(false));
} else {
item.add(new Label("entryBody", entry.getBody()).setEscapeModelStrings(false));
}
DateFormat df = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG, getBlog().getLocale());
item.add(new Label("entryDate", df.format(entry.getDate())));
}
});
add(new Label("pageTitle", getBlog().getName()));
}
}
<wicket:extend>As you can see, I just created a web page using mostly Java, with only a very tiny html code that tells wicket where and how to render components. Also take note that the wicket:id attribute can be assigned to almost any HTML tag. Now, I won't go into too much detail about how Wicket's model work right now (I have to save something for a later post, don't I?), but let's just say that Wicket offers model separation, from the domain objects, to the wicket model objects by means of a couple of interfaces, like IModel.
<div class="blogEntry" wicket:id="blogEntries">
<h3 wicket:id="entryTitle">[Blog Entry Title]</h3>
<div wicket:id="entryBody">[Blog Entry Body]</div>
<p><a href="#" wicket:id="viewBlogEntry">Read more</a></p>
<p>Posted on <span wicket:id="entryDate">[Blog Entry Date]</span></p>
</div>
</wicket:extend>
An interesting thing that I will point out is that the "Read more" link is conditionally displayed by overriding the isVisible method of a BookmarkablePageLink (as shown in bold), and not inside the html (or jsp) as people are usually accustomed to do with other frameworks. This covers our main page, now let's see how the other pages are done.
Blog detail Page
This page is actually very simple, with one exception. Here's the code:
package org.javageek.wicket;and here's the html:
import java.text.DateFormat;
import wicket.PageParameters;
import wicket.markup.html.basic.Label;
import domain.Blog;
import domain.BlogEntry;
public class ViewBlogEntry extends BasePage {
public ViewBlogEntry(PageParameters parameters) {
super();
Blog blog = getBlog();
BlogEntry entry = blog.getBlogEntry(parameters.getString("id"));
if(null == entry) {
redirectTo(new PageNotFound());
} else {
add(new Label("entryTitle", entry.getTitle()));
add(new Label("entryBody", entry.getBody()).setEscapeModelStrings(false));
add(new Label("pageTitle", entry.getTitle() + " : " + blog.getName()));
DateFormat df = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG, getBlog().getLocale());
add(new Label("entryDate", df.format(entry.getDate())));
}
}
}
<wicket:extend>One thing to note with this page is that I'm overriding a constructor from WebPage that provides me with the page parameters as sent in the GET or POST request, conveniently wrapped as a Map object. Also, if any of these parameters (in our case an invalid entry id) produce a null entry (not found), I redirect the user to the PageNotFound class.
<div class="blogEntry">
<h3 wicket:id="entryTitle">[Blog Entry Title]</h3>
<div wicket:id="entryBody">[Blog Entry Body]</div>
<p>Posted on <span wicket:id="entryDate">[Blog Entry Date]</span></p>
</div>
</wicket:extend>
This is the code for the PageNotFound class, and basically it just sets the response status to 404:
package org.javageek.wicket;(As a side note, It took me a while to get the 404 page to work, and I had to ask for help. Fortunately, the people from Wicket are very accesible and they have an irc channel at freenode, ##wicket, where they usually hang out. They also pointed out that this is much easier to do in Wicket 1.2, as you can throw an Exception instead of using the redirectTo method, which has a couple of quirks.)
import wicket.markup.html.basic.Label;
import wicket.protocol.http.WebResponse;
public class PageNotFound extends BasePage {
public PageNotFound() {
add(new Label("pageTitle", BlogApplication.instance().getBlog().getName()));
}
@Override protected void configureResponse() {
WebResponse wr= getWebRequestCycle().getWebResponse();
wr.getHttpServletResponse().setStatus(404);
}
}
And that's it. I just created a web application using Wicket.
Summary
Wicket, in my opinion, focuses the development efforts in the right place, inside plain Java code, and leaves the graphical presentation where it should be, inside html. At first you might find a little hard to grasp this paradigm shift, as so many developers are being 'forced' to rely on jstl and jsp scriptlets to accomplish logic programming for a page with all the other frameworks. But once you get used to this, I'm sure wicket will provide really fast development times.
I am making the source available (under the Apache 2.0 License) if you want to check the code, although I posted everything except for the domain part on this article. You can use it as an introduction to Wicket, if you like. I hope you find something here useful.
Also, I want to thank Igor Vaynberg for his help with the source code, in particular the Model parts.
Re: Comparing Web Frameworks: Wicket
I'm not sure I understand your comment. Do you think Java web development takes forever because it took me one month to write the article, or because of 'all' the code you have to write?
I have to say that writing the example code took me 2 days, from start to finish, working mostly after hours. And it was the first time I actually got into learning Wicket (i.e. no prior knowledge).
So, why do you think creating web applications in Java take forever?
Re: Comparing Web Frameworks: Wicket
Re: Comparing Web Frameworks: Wicket
It might be worth mentioning that with all of the recent AJAX buzz, Wicket has an excellent API for building Web 2.0 applications.
I've written a number of AJAX applications with Wicket, and it has easily been the best framework I've used thus far.
http://jroller.com/page/wireframe/?anchor=choice_is_goodhttp://jroller.com/page/wireframe/?anchor=new_draggabletarget
http://jroller.com/page/wireframe/?anchor=auto_previewable_wicket_pages
Re: Comparing Web Frameworks: Wicket
I am trying to see how this format saves any time. This is like reverse polish notation to me. While it might be technically effective, it doesn't appear to be readable or developer friendly. Does this look like self documenting code to you?
I am trying to understand why you have to override so much rather than setting properties or event handlers if in fact this is an event driven framework. If the page or a page fragment defines its structure, why isn't that structure passed to my Java code as a pre-instantiated model tree/tree fragment that I can then set properties thereof?
On the Index page, instead of working with my domain objects directly, it appears you have to constantly retrieve and cast domain objects from the item model object. Why should I have to do this? For example, in the Index.populateItem method, why is that method not receiving an object tree that represents the elements that were defined in the template and then I fill in those instantiated elements with the appropriate data and set their properties or not accordingly. The code you have shown demonstrates that the developer has to know the elements that are defined in the template page and instantiate them. This is totally RPN.
This doesn't appear to be as productive as JSF/Facelets. I'm open to more examples but this isn't a convincing case.
Re: Comparing Web Frameworks: Wicket
Remember that the key words here are 'separation of concern'. Sure, I can create loops in JSP, but that means I have to use JSP. With Wicket, you can leave the HTML creation to web designers who can do their magic in styling and polishing of a page.
As for the overriding part, well, this is Java for you. In close-to-ideal-object-oriented frameworks, methods should be overriden, classes subclassed, etc.
Regarding the Index.populateItem method, you misread that one. I'm actually creating an anonymous inner class of ListView which overrides populateItem. That could've been an external class, but I wanted to include it inside to make it 'more readable' in the sense that all the code is there and not on another file. The ListView is an object tree that is added to the Index class.
The code you have shown demonstrates that the developer has to know the elements that are defined in the template page and instantiate them.
Well, separation of concern doesn't mean that the right hand doesn't knows what the left hand does. It means that both hands can work in parallel
Re: Comparing Web Frameworks: Wicket
I think the forest part is that separating out the /behavior/ into Java gives you incredible leverage that you cannot get by intertwining behavior and markup. To really see this, you have to play around with Wicket for a while I think. You can actually do some extremely sophisticated things with Wicket. Some of the UIs I've seen in Wicket are kindof jaw-dropping when you imagine what it would take to do the same thing in JSP. Comparing a couple of read-only, or even editable lists really does not get to the heart of what makes Wicket better. You have to construct something more complex to see it. Try making a tree of panels, each of which edits a list. This is not actually all that much code in Wicket. But try doing that in a JSP page!
As far as the listener methods go, Wicket is fully extensible in its listener methods, but actually hides quite a bit of this in its class hierarchy. You don't directly override the form submit listener for example because that is just an implementation details of "formness". Instead you override methods of Form to respond to more abstract concepts.
As far as model typing goes, this is coming in Wicket 2.0 when we introduce generics into Wicket models later this year (not much later, actually... Wicket 1.3 is going to be a very very quick cycle since we will only make one change in it... and then 2.0 will be immediately after that. if i had to guess, i'd guess that generic models ought to be here by June or so)
Re: Comparing Web Frameworks: Wicket
Re: Comparing Web Frameworks: Wicket
Re: Comparing Web Frameworks: Wicket
Re: Comparing Web Frameworks: Wicket
Re: Comparing Web Frameworks: Wicket
add(new Label("blogName" ...
I think there should be a default behaviour, where I can register an object with a page and all properties of that object are accessible in the HTML. This would reduce the amount of code for forms with many fields/labels tremendously.
2) I really hate struts for its tag library with its quirks populating drop-down boxes etc. but I do not understand the necessity to wrap everything in IModel and the like
3) "Try making a tree of panels, each of which edits a list. This is not actually all that much code in Wicket. But try doing that in a JSP page!" Show me.
4) I really would like to know more about the advantage/disadvantages w.r.t. Tapestry.