Archive for category: Wicket Tutorials

Automatically test your Wicket panel HTML markup

Automatically test your Wicket panel HTML markup

Are you testing your HTML markup automatically yet? If your markup does not match the Java code, your Wicket panel does not work. It’s easy to get early feedback when your panels are broken: just unit test them!

In this blog post I describe a way of automatically verifying that the HTML markup of Wicket panels match the Java code. Scroll down to download the demo project!

Unit test

Unit testing Wicket panels with EclipseI created a JUnit test that you can add to your project to automatically test as much Wicket Panels as possible. Automatic testing works by resolving all panels on the Java class path and feeding them to the WicketTester. When a panel has invalid markup, the WicketTester will give an error: early feedback!

How does it work?

The Wicket panels that can automatically be tested should have a ‘default’ Wicket constructor, like this:

public DemoPanel(String id)

Resolving all panels is done with Spring 2.5’s ClassPathScanningCandidateComponentProvider (don’t you love those names! How can they stay below 120 characters per line?)

The ClassPathScanningCandidateComponentProvider is a component provider that scans the classpath from a base package. It then applies exclude and include filters to the resulting classes to find candidates.

Testing panels

@Test
    public void testAllWicketPanels() throws Exception {
        WicketTester wicketTester = new WicketTester(new WicketApplication());
 
    	ClassPathScanningCandidateComponentProvider provider = new ClassPathScanningCandidateComponentProvider(true);
        provider.addIncludeFilter(new AssignableTypeFilter(Panel.class));
 
        Set components = provider.findCandidateComponents("nl/stuq/demo");
        for (BeanDefinition component : components) {
            Class clazz = Class.forName(component.getBeanClassName());
            if(hasDefaultConstructor(clazz)){
            	testWicketPanel(wicketTester, clazz);
            }
        }
    }
 
    private void testWicketPanel(WicketTester wicketTester, Class clazz) {
    	wicketTester.startPanel(clazz);
    	wicketTester.assertNoErrorMessage();
    	wicketTester.assertNoInfoMessage();
    }
 
    private boolean hasDefaultConstructor(Class clazz) {
        for(Constructor constructor : clazz.getConstructors()){
            if(constructor.getParameterTypes().length == 1 &&
               constructor.getParameterTypes()[0].getSimpleName().equals("String")){
                return true;
            }
        }
 
        return false;
    }

The test instantiates a new WicketTester. After that, the ClassPathScanningCandidateComponentProvider is created and configured to scan only for Panel classes in the nl.stuq.demo package and below.
After that, the found components are all checked. If they have a default constructor, the test is executed.

The boolean hasDefaultConstructor(clazz) method checks if the class has a constructor with only one String argument, the Wicket id.

Keep in mind

  • This is only for lazy people (good developers are lazy in some ways).
  • You need a dependency to Spring.
  • Only Panels with a certain constructor are tested.
  • Only instantiating the Panel is tested, so code coverage has no meaning for this test. Real testing is still needed.

Download demo project

The demo project is a Maven project based on the Wicket 1.4.3 quickstart that contains the test class and an example panel to be tested.
Download demo project.

Extract the zip file and run mvn test to run the tests. Then fire up your IDE and check how it’s done.

You can change or adapt the given JUnit test to also automatically test classes extending from Page or Component.

Join in with your opinions and code! I’m curious to see what clever way you have of testing code.

November 1, 2009 5 comments Read More
User friendly form validation with Wicket

User friendly form validation with Wicket

By default Wicket shows error messages together in a single place in the HTML form. This has some drawbacks to usability, especially if you have long forms with lots of fields. Read further for a tutorial exploring possibilities to improve the location of the error on the page, thereby improving usability.

The default FeedbackPanel shows all errors in one place. When you enter a wrong value in an input field below the fold, the input field is a mile away from the error above the form. This makes it unclear which error message corresponds to which field.

form-usability-scanning.png

The image on the left shows that a lot of page scanning is needed even with moderate sized forms.

With more than a few fields, the user is confused as which error corresponds to which field. It is a big problem when your e-commerce site scares away many potential clients who can’t complete your web forms!

The default form

Before I describe how to create a more user friendly form, first the ‘default’ form. The following is an example of a standard Wicket form. This kind of form is the one you get without doing any ‘special’ magic things. Place your mouse cursor over the image to see the default error messages above the form.

Default Wicket form with FeedbackPanel at the top

This form will be the starting point for our improvements.

The improved form

This is what we are going to make:

Better and improved Wicket form with FeedbackLabels throughout

As you can see, the error messages are directly next to the component that caused the error. This reduces the scanning of the page to link the error message to the right form component.

Step 1: Introducing the FeedbackLabel

The FeedbackLabel is a custom component I’ve written for this tutorial. With this custom label, you can show important feedback messages related to a FormComponent.

This has the advantage that you can place your Feedback messages in any place you want.

Add this to the Java part of the form:

// This shows feedback when the name input is not correct.
FeedbackLabel nameFeedbackLabel = new FeedbackLabel("name.feedback", name);
form.add(nameFeedbackLabel);
 
FeedbackLabel colorFeedbackLabel = new FeedbackLabel("color.feedback", color, customText);
form.add(colorFeedbackLabel);

Add another SPAN tag for every feedback label. You can place this near the relevant form component within the form.

Step 2: Removing the FeedbackPanel completely? No, filtering!

At first, it looks like you can remove the FeedbackPanel completely. But, then you will not be able to use the info() method to display text inside the FeedbackPanel! Therefore we need a way to filter the FeedbackMessages so error messages are not shown. I have written a FeedbackMessageFilter to accomplish that. It filters out the unwanted error messages.

// filteredErrorLevels will not be shown in the FeedbackPanel
int[] filteredErrorLevels = new int[]{FeedbackMessage.ERROR};
feedback.setFilter(new ErrorLevelsFeedbackMessageFilter(filteredErrorLevels));

I have included the ErrorLevelsFeedbackMessageFilter in the project files, so you can reuse this in your existing projects. Remember if you use the error() method, you cannot use this filter! Instead, create your own filter that filters based on components.

Step 3: Adding some style, the ComponentVisualErrorBehavior™

I always love extremely long class names, like the BookmarkablePageRequestTargetUrlCodingStrategy or the SharedResourceRequestTargetUrlCodingStrategy. It makes my day to introduce a class name consisting of four words, the ComponentVisualErrorBehavior™.

This behavior changes the CSS styles for components that are invalid according to the Wicket form validation. You see in the screenshot that the textfield has a red line around it. This is the result of the ComponentVisualErrorBehavior. You can easily change the styles that are applied.

form-usability-tutorial-namefield.png

To add the ComponentVisualErrorBehavior to your component, just add one line in your Java code:

name.add(new ComponentVisualErrorBehavior("onblur", nameFeedbackLabel));

“onblur” stands for the event that triggers this Behavior. The nameFeedbackLabel will also be updated when this is triggered, so that it will show the relevant error (or nothing if the input is valid).

Download

Download the complete example project and start experimenting! (run with mvn jetty:run and connect to http://localhost:8080/demo)

Let me know how and where you use it in the comments!

September 3, 2008 43 comments Read More
Create RESTful URLs with Wicket

Create RESTful URLs with Wicket

This is a tutorial on using Wicket with REST-style URLs. Normally, Wicket generates URLs that are a bit ugly.
For example:

http://www.example.com/wui/?wicket:bookmarkablePage=%3Anl.stuq.demo.SomePage.

Ugly!

RESTful URLs change that: they are more meaningful for the user, hide some of your implementation details, and are just beautiful. Plus, you’re joining one of the latest hypes. Life couldn’t be better…

Looking around on the intertubes, there is not much useful information about using RESTful URLs in Wicket. Because I need this for a project I’m currently working on, I decided to turn this into a small tutorial.

What is REST?

Representational State Transfer (REST) is a software architectural style for distributed hypermedia systems like the world wide web. The best way to explain this, is an example. A REST application might define the following resources:

  • http://example.com/users/
  • http://example.com/users/{user} (one for each user)
  • http://example.com/findUserForm
  • http://example.com/locations/
  • http://example.com/locations/{location} (one for each location)
  • http://example.com/findLocationForm

This is a very, very short explanation of only a small part of what REST does. More information, as always, can be found on Wikipedia.

When you use custom URLs, you effectively hide some of your internal structure behind more meaningful URLs. This means you can refactor more easily without breaking external links or bookmarks to a specific part of your site. This is also important for search engine optimization.

Note: I’m not going to describe here when you should or should not use REST
with Wicket. That’s an architectural discussion, which depends greatly
on your project. I have discovered some limitations in the Wicket development model that prevent the full implementation of REST. Please read further for more information.

First steps

I suggest you download the code first and read along during the rest of this post.

We are going to create a customer overview page and a products overview page, reachable on “http://example.com/customers/” and “http://example.com/products/”.

The HomePage has two links, to the customer list and the product list. The product and customer lists have links to each individual product (http://example.com/products/${ID}) and customer (http://example.com/customers/${ID}).

For the Wicket UI, I created a HomePage, which links to the CustomerOverviewPage and ProductOverviewPage, which link to the Customer and Product detail pages. To serve up the data, we have some simple services, a ProductService and a CustomerService.

The code

Wicket has a nice built in method of declaring (mounting) custom URL schemes. Simply give a class which implements the IRequestTargetUrlCodingStrategy interface to a WebApplication.

public final void mount(IRequestTargetUrlCodingStrategy encoder)

Relatively new in Wicket is the MixedParamUrlCodingStrategy, which we will use in a minute.

This is an example of how to use the MixedParamUrlCodingStrategy in your WebApplication class:

        public WicketApplication()
        {
        MixedParamUrlCodingStrategy productURLS = new MixedParamUrlCodingStrategy(
                "products",
                ProductDetailPage.class,
                new String[]{"id"}
        );
        mount(productURLS);

This means:

  • "products"

    This is the part of the URL after the Wicket’s application URL. In this case: “http://www.example.com/products

  • ProductDetailPage.class

    This defines for which class this URL is meant. In our project, the ProductDetailPage shows a product’s details.

  •  new String[]{"id"}

    This is a list of all the parameters that you want to pass to this page. This shows up in the URL like this: “http://www.example.com/products/23” for a product with ID 23. You can easily pass more parameters to this page by adding items to this String array.

  • mount(productURLS);

    This passes this MixedParamUrlCodingStrategy to the WebApplication.

The Product detail page

The ProductDetailPage receives these URL parameters in the following way:

public ProductDetailPage(PageParameters parameters) {
int id = parameters.getInt("id");

After that, you can get the Product with this ID (the rest of the code can be downloaded below):

setModel(new CompoundPropertyModel(productService.getProduct(id)));
 
add(new Label("id"));
add(new Label("name"));
 
add(new BookmarkablePageLink("backLink", getApplication().getHomePage()));

Limitations of Wicket

It is currently not possibly (without doing a workaround outside Wicket) to do HTTP PUT, DELETE and POSTs to arbitrary URLs. If you do know how to achieve this, you are very welcome to post it in the comments.

Further steps

In the above tutorial we configured the URL’s in the WebApplication init() method. This has the drawback that information about a single page is in muliple places. It is good from an architecture perspective to configure the URL’s from the Page itself. Look at the wicket-stuff annotation project for more information on how to do that. You can find an excellent tutorial there. The wicketstuff-annotation library is used to mount your pages declaratively via Java annotations.

Further reading

Download

Download the complete example project and start experimenting! (run with mvn jetty:run and connect to http://localhost:8080/demo)

Let me know how and where you use it in the comments!

June 20, 2008 7 comments Read More
Wicket: how to write a reusable modal window popup

Wicket: how to write a reusable modal window popup

Wicket is a Java framework for creating web frontends. It allows you to create a webpage in Java, combining all kinds of components into one page.

In many projects, a subset of user interface elements are repeated over the site. Depending on your project, you can have different selection panels or popups that are used multiple times.

In the following tutorial I describe a method to write your own application specific reusable modal window popup.

Start!

For this example, we use the ModalWindow component from Wicket Extensions.If you don’t know what a ModalWindow looks like, you can see a demo. (hint: try to drag and drop it or resize it)

The example from Wicket extensions

The default example from the Wicket Extensions site contains no real reusable components, besides the ModalWindow itself. The Page inside the ModalWindow is tightly coupled to the ModalWindow. It closes its containing ModalWindow and sets a result parameter of the parent page. The components can only be reused in exactly the same way.

How can we make this more reusable?

We can make this more reusable by making the content of the ModalWindow not aware of the ModalWindow itself. The content does not know what will happen when the containing Form (or other data) is submitted. But how can we do that? The magic words are: abstract methods.

Before we start, you can download the code here, so you can get the complete picture.

The image on the right contains the structure of the page and the components we are creating. The page contains a modal window, which in turn contains a content panel.

The Content Panel

Lets start with the content panel inside the ModalWindow popup. This panel contains a selection link, a selection button and a cancel button, created in the constructor:

public SelectContentPanel(String id) {
  super(id);
 
  // Create the form, to use later for the buttons
  Form form = new Form("form");
  add(form);
 
  // Add some example 'selection' methods, to show as example
  // You can also use a full fledged form, I left that as an
  // exercise for the reader :-)
  add(new AjaxLink("selectionLink"){
    public void onClick(AjaxRequestTarget target) {
      onSelect(target, new String("Selection using the link."));
    }
  });
 
  form.add(new AjaxButton("selectionButton"){
    protected void onSubmit(AjaxRequestTarget target, Form form) {
      onSelect(target, new String("Selection using the button."));
    }
  });
 
  // Add a cancel / close button.
  form.add(new AjaxButton("close") {
    public void onSubmit(AjaxRequestTarget target, Form form) {
      onCancel(target);
    }
  });
[..]

HTML:

  <a>Select something</a> 
<form>
<input type="button" value="Select something else" />
<input type="button" value="Close" />
  </form>

You probably noticed the calls to onSelect() and onCancel(). These are the abstract methods we are declaring:

abstract void onCancel(AjaxRequestTarget target);
abstract void onSelect(AjaxRequestTarget target, String selection);

These methods are abstract, that way the code that is calling this panel must implement these methods. Because we are calling these methods, this effectively gives the result to the consuming code, without ever knowing what will happen with it.

To use abstract methods, the class itself must be abstract:
public abstract class SelectContentPanel extends Panel

The Modal Window

The Modal Window initializes itself with some values. You can just as easily set these values from the calling class, but for now we keep it local.

public SelectModalWindow(String id) {
    super(id);
 
    // Set sizes of this ModalWindow. You can also do this from the HomePage
    // but its not a bad idea to set some good default values.
    setInitialWidth(450);
    setInitialHeight(300);
 
    setTitle("Select something");
 
    // Set the content panel, implementing the abstract methods
    setContent(new SelectContentPanel(this.getContentId()){
        void onCancel(AjaxRequestTarget target) {
            SelectModalWindow.this.onCancel(target);
        }
 
        void onSelect(AjaxRequestTarget target, String selection) {
            SelectModalWindow.this.onSelect(target, selection);
        }
    });
}

HTML:

  <a>Select something</a> 
<form>
<input type="button" value="Select something else" />
<input type="button" value="Close" />
  </form>

The setContent() function call is interesting. Here we create a new SelectContentPanel and implement the methods onCancel() and onSelect(). It is possible to do some extra actions here, but here it is passed one-on-one to the abstract methods of the ModalWindow itself:

abstract void onCancel(AjaxRequestTarget target);
abstract void onSelect(AjaxRequestTarget target, String selection);

The Home Page

The Home Page itself can now instantiate the ModalWindow, override the methods and do something with the data. One big advantage is that you can see from the HomePage class directly what is going to happen after the user selects something or cancels the action:

final ModalWindow selectModalWindow = new SelectModalWindow("modalwindow"){
 
  void onSelect(AjaxRequestTarget target, String selection) {
    // Handle Select action
    resultLabel.setModelObject(selection);
    target.addComponent(resultLabel);
    close(target);
  }
 
  void onCancel(AjaxRequestTarget target) {
    // Handle Cancel action
    resultLabel.setModelObject("ModalWindow cancelled.");
    target.addComponent(resultLabel);
    close(target);
  }
 
};
 
add(selectModalWindow);

Further customization

This example is just passing a String around, you can change it to a more specific class. You can change the onSelect to something more appropriate for your use case. You can even put a Form inside the panel and return the resulting object of the form.

Download

Download the complete example project and start experimenting!
(run with mvn jetty:run and connect to http://localhost:8080/demo)

If you think this is useful, please let me know in the comments.

June 5, 2008 30 comments Read More