Wicket Impressions 1
I chose Wicket for this project, partly because I met some people who were very enthusiastic about the framework, and partly because I wanted something that was easily tested. My client requires a Java solution, so Ruby on Rails was out. I did a quick little shoot out between three Java framework options, and Wicket passed the first impression stage.
Now I’ve got a couple of iterations of software development with it under my belt and I’m starting to feel a bit more comfortable with the framework. As far as Java web frameworks go, its pretty good, but… I would do things a bit differently. The application is written in a style that would actually better fit Ruby, SmallTalk, Lisp, or some language that supported passing in procedures or lambdas (as the language gurus call them) natively. Take for instance the Link class. In order to do anything useful, you need to subclass and implement the onClick callback method—even if all you want is to go to another page. Here is an example:
add(new Link("wicketId") {
@Override
public void onClick() {
// do fancy logic
setResponsePage(new IncidentPage(incident));
}
});
If this were Ruby the code would look like something like this:
self << Link.new("wicketId") do
// do fancy logic
respond_with(IncidentPage.new(incident)
end
So am I complaining about semantics? Possibly. However, there are more “Java” ways of accomplishing the same class—particularly if you want to manage all business logic in a few classes. The more “Java” way would be something like using the java.lang.Runnable interface. That would allow you to set up an enum to include all your business logic like this:
enum IncidentLogic implements Runnable {
EDIT {
@Override
public Page run() {
// do fancy logic
return new IncidentPage(incident);
}
}
}
and it would be used in your page like this:
add(new Link("wicketId", IncidentLogic.EDIT));
I’ve also experimented with using a dynamic proxy to bind any method to an interface. That would let you set up a logic utility class and reference it like this:
add(new Link("wicketId", Linker.link(IncidentUtility.class, "edit"));
It’s not as pretty but it works. Now here’s the nice thing about Wicket. If I feel strongly enough about it, I can create my own subclass of the Link object to implement that approach myself. My DynamicLink would look something like this:
public class DynamicLink extends Link {
public static interface Executable {
Page do();
}
private final DynamicLink.Executable click;
public DynamicLink(String wicketId, DynamicLink.Executable action) {
super(wicketId);
this.click = action;
}
@Override
public void onClick() {
setResponsePage(click.do());
}
}
In fact, I think I may just do that. It’s better than having bits and pieces of behavior spread throughout the Pages and panels defined in the application. I think I find it a bit frustrating when i need to do things like that just to format dates the way I want. Why can’t the provided DateFormatter let you set the pattern you wanted to use? Why do I have to subclass the one in Wicket just to get that feature?
At the end of the day, my complaints are minor and the Wicket community is helpful. I’m fine with that. The Wicket framework is probably one of the leaders in providing a test harness that can be used easily in your JUnit tests. That is a much bigger selling point to me.
Wicket, Spring, Hibernate, Testing... Yeah, it's like that.
I have to deliver a product using Java. Due to politics and approved baselines, etc. I can’t use Ruby on Rails. I’ve done my own thing in the past, and so this time I decided to save some time by incorporating Wicket, Spring, and Hibernate using auto-wiring, and attributes. Getting it all to talk together took the better part of a day, but I got it to deploy and run fine.
I’m an avid unit tester, so I was happy to learn that Wicket has some facilities to make testing a bit easier without forcing you to create your own Servlet mock objects. I was really happy about that, so I decided to try it out. Unfortunately, I ran into a rather nasty roadblock. Spring was complaining about the ContextLoaderListener not being loaded. It’s defined in my web.xml file, but the autowiring requires the spring context to be loaded in a particular location. Finding out how to fix that problem took me the better part of half a day.
The problem is that Wicket hides the ServletContext object away from you. You can’t add values, because the test framework is initialized on construction. Attempts to obtain the ServletContext and manually add the Spring web application context just weren’t working. That’s because it is configured when the WicketTester object is constructed and ignored after that. I needed to be able to inject my own ServletContext with the Spring integration taken care of. I finally figured it out here, because the forums just working for me. Please note that this is tested with Wicket 1.4 and not any of the earlier versions:
final MyApplication app = new MyApplication();
tester = new WicketTester(app) {
@Override
public ServletContext newServletContext(final String path) {
// web context
ServletContext context = new MockServletContext(app, path);
// spring context
XmlWebApplicationContext spring = new XmlWebApplicationContext();
spring.setServletContext(context);
// configure spring
spring.setConfigLocation("classpath:application.xml");
// put spring where Wicket can find it
context.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, spring);
return context;
}
};
So let me explain what I did. I created an anonymous subclass of the WicketTester class so I could override the factory method “newServletContext” to inject my spring configuration. Done properly, the wicket folks can take care of this by providing a SpringWicketTester subclass in their spring integration library. The SpringWicketTester would let you specify the location of your Spring configuration file, and it would override that method for you. For now, you’ll have to do it yourself.
I put the WicketTester initialization in a subclass of the JUnit TestCase class. That way I don’t have to repeat myself for setting up my Wicket testing.
Java ActionPack: Inheritance Design Process
My Java ActionPack package is coming along rather nicely. For those who don’t know, it was designed on the founding principles of Ruby on Rails (or at least its ActionPack portion), but evolved in a Java way. I shouldn’t need to state the obvious, but Ruby and Java are different languages. Frameworks developed on them will be different because they have different affordances 1 so they will take different evolutionary paths even if they are founded on the same principles.
I added a feature to make controller inheritance work better. It‘s natural to assume that all the filters and actions from a parent class are present in the child class. You get that for free (to a certain extent) with the language itself. But what about the views associated with a controller? In my real world example, I have a base “Message“ type and a base Message Controller that provides the core functionality to the user. I also have several (at least potentially) subtypes of messages, and I need to allow specialization for those message types. Really I want everything to be the same, but only override the message display (for the header information). I wanted to be able to create the “Cable“ controller and then only provide an override for the “header“ action and leave everything else the same. Since views are separate animals from the controller, and the view selection is based on the controller name, there was a problem.
If I set my browser to “cable/list“ I wouldn‘t get the list of cables as expected. I got a 404 error. I decided that the best way to provide expected behavior when we link controllers and views like this was to key the view name off of the controller that implemented a method. Since the list action and associated view was created on the message controller, the framework now detects that and shows the message/list view. When I override the “cable/header“ method and create the “cable/header” view, I have the specialized view.
It‘s a long way around to say that the view controller mapping is inherited so that the whole web application becomes object oriented, so to speak. It builds on the same knowlege that we take for granted in OOP, and maintains those same expectations. It‘s actually a fairly simple solution to a simple problem — assuming you are thinking in OOP terms.
