July 22, 2009

Why Previous Java Web Framework Have Failed and Why Apache Wicket Will Succeed.

There exists numerous Java web framework (e.g. Struts, JSF, Spring MVC, etc.) and most of them are build upon the Model-View-Controller pattern, but though they have been used in numerous successful project, the Java community still produces new Java web framework. Why is that? According to me the previous Java web framework have several flaws:
  • The JSP technique is messy and clutters down the view page, maybe not for simple pages, but definitely for more complex pages.
  • The round trip when developing JSP pages is long since JSP pages can not be viewed, without first compiling them and running them in a web container. This severely slows down the project . This is especially true when one is fixing layout issues.
  • Web and JSP developer have different code base. This also slows down the project productivity, since when the web team ships new code or fixes, the JSP developer must copy past that into different JSP code.
  • Verbose XML configuration, is something the entire Java community is trying to get away from via Annotation and better default values. For example look at the EJB or Spring developing.
  • It is hard and verbose to unit test and even harder to maintain.
Though these many flaws there has not been any good alternative around to develop Java web solution, but now I would say the missing link is found – Apache Wicket.

The Apache Wicket architecture differs in two major way.
  • It does not use JSP technology for coding Views, instead it uses simple HTML and extend it with attributes.
  • You create components (TextField, CheckBox, etc.) in the Controller and add behavioral via Listener classes, such as in Swing.
These two major differences make a huge different:
  • Web and View developer use the same code base.
  • No need to compile and run the View in a container, simply open the View in a web browser and watch differences.
  • Easy to write unit test code.
Before going through an example, lets first take a brief overview over the main Wicket classes. Component are simple Java classes with supporting HTML markup.
Each Components holds a Model that is a simple Java class with data.

What is here imported is that the default Model are stateful and most example for Wicket uses the default model. This is unfortunate because that is not best practice, because stateful objects consume memory and make the application less scalable. The two most imported classes two use to make the application stateless is

IModel usersModel = new LoadableDetachableModel() {
protected Object load() {
return WicketApplication.get().getUserService().getUsers();
}
};

and

new BookmarkablePageLink(“newUser”, UserEditPage.class);

and if you need to pass data use Link with as little data as possible.

Link view = new Link("editUser", itemList.getModel()) {
public void onClick() {
setResponsePage(new UserEditPage(user.getUserId()));
}
};

Now look how easy and clean the unit test is:

public class UserEditPageTest extends TestCase {
protected static final Logger log = Logger.getLogger(UserEditPageTest.class);
private WicketTester tester;

public void setUp() {
tester = new WicketTester(new WicketApplication());
}

private void setUpNewUserEditPage() {
tester.startPage(UserEditPage.class);
tester.assertRenderedPage(UserEditPage.class);
}

public void testLayout() {
setUpNewUserEditPage();

tester.assertComponent(UserEditPage.FEEDBACK_PANEL, FeedbackPanel.class);
tester.assertComponent(UserEditPage.USER_FORM, Form.class);
}

public void testNewUser() {
setUpNewUserEditPage();

FormTester form = tester.newFormTester(UserEditPage.USER_FORM);
form.setValue(UserEditPage.USERNAME, "kalle.stropp@fake.com");
form.setValue(UserEditPage.PASSWORD, "validpassword");
form.select(UserEditPage.ROLES, 0);
form.submit(FormBuilder.BUTTON_SAVE);

tester.assertRenderedPage(UserListPage.class);
tester.assertNoErrorMessage();
}
}


And here follows the rest of the code:


public class UserEditPage extends TemplatePage implements ButtonListener, IChoiceRenderer {
private static final long serialVersionUID = 1L;
protected static final String FEEDBACK_PANEL = "feedbackPanel";
protected static final String USER_FORM = "userForm";
protected static final String USER_ID = "userId";
protected static final String USERNAME = "username";
protected static final String PASSWORD = "password";
protected static final String ROLES = "roles";
protected static final Logger log = Logger.getLogger(UserEditPage.class);

public UserEditPage() {
setModel(new CompoundPropertyModel(new LoadableDetachableModel() {
private static final long serialVersionUID = 1L;

protected Object load() {
return new User();
}
}));
init(false);
}

public UserEditPage(final long userId) {
setModel(new CompoundPropertyModel(new LoadableDetachableModel() {
private static final long serialVersionUID = 1L;

protected Object load() {
User user = WicketApplication.get().getUserService().loadUser(userId);
user.setPassword(null); // hide current password
return user;
}
}));
init(true);
}

protected String getPageTitle() {
return "userEditPage.title";
}

public void init(boolean readOnly) {
add(new FeedbackPanel(FEEDBACK_PANEL));
add(createForm(readOnly));
}

public Form createForm(boolean readOnly) {
FormBuilder builder = new FormBuilder(USER_FORM, getModel());
builder.addLabel(USER_ID);
builder.addTextField(USERNAME, true, 30, readOnly);
builder.addPasswordTextField(PASSWORD);
User user = (User) builder.getModelObject();
builder.addDropDownChoice(ROLES, Arrays.asList(user.getRoles().getValues()), this);
builder.addSubmitButton(this);
return builder.create();
}

@Override
public void onSubmit(Object modelObject) {
log.info("onSubmit " + modelObject);
WicketApplication.get().getUserService().storeUser((User) modelObject);
setResponsePage(UserListPage.class);
}

@Override
public Object getDisplayValue(Object object) {
return ((Roles) object).getRole();
}

@Override
public String getIdValue(Object object, int index) {
return ((Roles) object).getRole();
}
}


And the HTML


<html >
<head > </head >
<body >

<wicket:extend >

<div wicket:id="feedbackPanel" >Feedback Panel </div >

<form wicket:id="userForm" >
<fieldset style="width:250px;" >
<legend > <wicket:message key="userEditPage.userForm" >User Form </wicket:message > </legend >
<table >
<tr >
<td align="right" > <wicket:message key="userEditPage.userId" >UserId </wicket:message >: </td >
<td > <span wicket:id="userId" id="userId" >1 </span > </td >
</tr >
<tr >
<td align="right" > <wicket:message key="userEditPage.username" > <u >U </u >sername </wicket:message >: </td >
<td > <input wicket:id="username" type="text" name="username" accesskey="u" / > </td >
</tr >
<tr >
<td align="right" > <wicket:message key="userEditPage.newPassword" >New <u >p </u >assword </wicket:message >: </td >
<td > <input wicket:id="password" type="password" name="password" accesskey="p" / > </td >
</tr >
<tr >
<td align="right" > <wicket:message key="userEditPage.roles" > <u >R </u >oles </wicket:message >: </td >
<td > <select wicket:id="roles" > </select > </td >
</tr >
<tr >
<td colspan="2" align="right" >
<button wicket:id="save" type="submit" accesskey="s" > <wicket:message key="userEditPage.save" > <u >S </u >ave </wicket:message > </button >
</td >
</tr >
</table >
</fieldset >
</form >

</wicket:extend >

</body >
</html >

8 comments:

Anonymous said...

Here is an article that explains why Wicket will fail on its turn:

http://www.theserverside.com/news/thread.tss?thread_id=54866#320116

Magnus K Karlsson said...

Apache Wicket is of course not the last Java Web Framework, but I would say it is the best framework of all the frameworks with the biggest community. The suggested framework lack two thing, at a quick look:

1. Big community
2. Written from scratch so that code will be easy to test and mocked.

Rene said...

Magnus, have you seen Hamlets?

Hamlets (previously known as IBM Servlet-based Content Creation Framework) is an open source system for generating dynamic web-pages developed by René Pawlitzek at IBM. A Hamlet is a servlet extension that reads XHTML template files containing presentation using SAX (the Simple API for XML) and dynamically adds content on the fly to those places in the template which are marked with special tags and IDs using a small set of callback functions. A template compiler can be used to accelerate Hamlets.

Hamlets provide an easy-to-use, easy-to-understand, lightweight, small-footprint, servlet-based content creation framework that facilitates the development of Web-based applications. The Hamlets framework not only supports but also enforces the complete separation of content and presentation. It is the result of a radical software simplification effort.

Magnus K Karlsson said...

Thanks for your comment Rene. I embrace new framework trying to think out of the box and use simpler and faster to develop, view technologies rather than JSP. Using XHTML is good and promotes valid HTML pages, but that is not always welcomed by the web developing guys. They often use tool and trick and tips they previously had used, and thereafter relying on the browser to fix the problem. This is not satisfactory, but this is my real life experience as a consultant. So changing from plain HTML to valid and well-formed could be a big step for web developer. And for investors the look&feel is imported so they tend to listen more to the web developing guys rather than the system developers.

So making a new framework depending on XHTML could be a problem, when having one web-developer team and another team of system developers, and wanting them to share the same code base. Otherwise it sounds like a great framework, I will be thrilled to see how big community it will get.

Anonymous said...

Hi Magnus!

More than a year has passed. Do you still think that Wicket will succeed?

AlexSerov@hybridserverpages.com

Magnus K Karlsson said...

If I were to choose a Java Web Framework today I would look at how big this framework is. One way to do that is to use Google Trends.

Here I compare:
- apache wicket
- JavaServer Faces, part of the J2EE spec.
- spring mvc
- google web toolkit
- hybridserverpages)

http://www.google.com/trends?q=(apache+wicket)+,+(JavaServer+Faces)+,+(spring+mvc)+,+(google+web+toolkit)+,+(hybridserverpages)&ctab=0&geo=all&date=all&sort=1

Please play around with different search criterias to see different search results.

pariuri sportive said...

Useful information shared..I am very happy to read this article..Thanks for giving us nice info. Fantastic walk-through. I appreciate this post.

what is rakeback said...

If I were to choose a Java Web Framework today I would look at how big this framework is. One way to do that is to use Google Trends.

Here I compare:
- apache wicket
- JavaServer Faces, part of the J2EE spec.
- spring mvc
- google web toolkit
- hybridserverpages)