Archive for August, 2005

Wicket Page Counter Example

Tuesday, August 16th, 2005

Sometimes it is very helpful to read old messages in your mail archive. I found a short discussion where I promised Stefan Arentz that we would incorporate some code he sent to the mailinglist into our examples. Well, of course I forgot all about it, and just 5 minutes ago rediscovered his message and example. So without any delay: here’s a page counter component made in Wicket:

Stefan Arentz wrote:

As an experiment I create a little counter panel. The markup looks like this:



    123

And this is the code (quick hack, not thread safe):

public class Counter extends Panel
{
    static Map mCounters = new HashMap();
    private String mCounterName;

    public Counter(String componentName, String counterName)
    {
        super(componentName);
        mCounterName = counterName;
        Integer count = (Integer) mCounters.get(mCounterName);
        if (count == null) {
            count = new Integer(1);
        } else {
            count = new Integer(count.intValue() + 1);
        }
        mCounters.put(mCounterName, count);
        add(new Label("count", count.toString()));
    }
}

Pretty simple. And I can now make different counters for pages like this:

Markup:

Java:

add(new Counter("counter", "HomepageCounter"));

The fun part is, that this is a full fledged component, that can be put in a jar, put in the classpath of your webapplication, and all you have to do is use the two little fragments at the end of the quote, to incorporate the hit counter in your page(s).

I like the simplicity of this example. It doesn’t take rocket science to create such a component. It doesn’t take any XML to create or use this component. Now that is where JSF still has something to gain.

New! Wicket Newsletter

Thursday, August 11th, 2005

I’ve created the first issue of the Wicket Newsletter. You can download it from here: http://wicket.sourceforge.net/downloads/newsletter-2005-08.pdf

Note that the statistics were a snapshot of last monday evening, European time. Since then, the tides have changed a little :-)

More Reference Manual Progress

Thursday, August 11th, 2005

This is yet another blurb from the work in progress on the Wicket reference manual. Again, this is just copied, and pasted, so no guarantees it looks great on your monitor. Feedback is always appreciated.

4.3. Processing User Input

In the following section you will learn what Wicket does when your user presses the submit button. It is possible to add multiple buttons to a form, so that you can perform different actions when the form is submitted. This is described in the section ‘Multiple Buttons’. It is also possible to bypass the Wicket form processing, which is described in ‘Advanced Form Processing’.

4.3.1. Submitting a Form

By default, the processing of a form works like this: The submitting button is looked up. A submitting button is a button that is nested in this form (is a child component) and that was clicked by the user. If a submitting button was found, and it has the immediate field true (default is false), its onSubmit method will be called right away, thus no validition is done, and things like updating form component models that would normally be done are skipped. In that respect, nesting a button with the immediate field set to true has the same effect as nesting a normal link. If you want you can call validate() to execute form validation, hasError() to find out whether validate() resulted in validation errors, and updateFormComponentModels() to update the models of nested form components. When no immediate submitting button was found, this form is validated (method validate()). Now, two possible paths exist:

1.

Form validation failed. All nested form components will be marked valid, and onError() is called to allow clients to provide custom error handling code.

2.

Form validation succeeded. The nested components will be asked to update their models and persist their data if applicable. After that, method delegateSubmit with optionally the submitting button is called. The default when there is a submitting button is to first call onSubmit on that button, and after that call onSubmit on this form. Clients may override delegateSubmit if they want different behaviour.

4.3.2. Multiple Buttons

As mentioned before, Wicket allows you to use multiple buttons in your form for submitting the form. Say you want to provide a ‘OK’ and a ‘Cancel’ button on your form. The markup is as follows:

Next we need to add the buttons and the code that needs to be performed when the button is pressed to the Java code:

public MyForm(String id, IModel model, IFeedback feedback) {
    ...
    add(new Button("button1") {
        public void onSubmit() {
            // do the OK bit
        }
    });
    add(new Button("button2") {
        public void onSubmit() {
            // do the cancel bit
        }
    });
}

When the user presses the ‘OK’ button (button1), then the onSubmit method of button1 is called. When the user presses the ‘Cancel’ button (button2), then the onSubmit method of button2 is called. Note that the onSubmit method is only called when the input is correctly validated. After the selected button has executed its submit method, the form’s submit is called. This behaviour can be altered by overriding the delegateSubmit(Button submittingButton) of class Form.

public class MyForm extends Form {
    ...
    protected void delegateSubmit(Button submittingButton) {
        if(submittingButton != null) {
            // submit the button
            submittingButton.onSubmit();
        }
        // don't submit the form
    }
}

4.3.3. Advanced Form Processing

TODO: still under considerable developmen

4.4. Adding Validation

In this section we will look at adding validation to your components, returning feedback to your users and give an overview of the validations Wicket provides.

4.4.1. Introduction

Each web application needs some sort of validation of user input. Wicket provides you with localized validations that are easy to add to your components and easy to create yourself. Giving feedback to your users is paramount to the succes of your application, so Wicket makes it easy to give excellent feedback to your users in their own language using the standard Java localization and internationalization support.

The basic structure of adding validation to your form components is the following:

*

add a feedback component to your page

*

register the feedback component with the form

*

add the validators to your form components

*

add validation messages to a resourcebundle

4.4.2. The Feedback loop

TODO: still under considerable development

4.4.3. Wicket Validations

Adding a validator to your components is not difficult: you need to get an instance of the validator (usually they are singletons) and add it to your component. The following code is taken from the form input example from the Wicket examples project.

… etc.

In the following sections we will add to each field a different validator.

4.4.3.1. Required Input

In order to force that input is available for a certain field, Wicket provides a RequiredValidator. The following code makes the first field in the example (wicket:id=”required”) a required field:

public MyForm(String id, IModel model, IFeedback feedback) {
    super(id, model, feedback);
    TextField field = new TextField("required", new PropertyModel(model, "text"));
    field.add(RequiredValidator.getInstance());
    add(field);
}

Note that instead of adding the RequiredValidator to the field, we could’ve used a RequiredTextField field. This is a Wicket component that does the validator administration for you:

public MyForm(String id, IModel model, IFeedback feedback) {
    super(id, model, feedback);
    RequiredTextField field = new RequiredTextField("required", new PropertyModel(model, "text"));
    add(field);
}

Adding the following feedback message to the MyPage.properties:

myForm.required.RequiredValidator=${name} is required.

The RequiredValidator only adds the ${name} parameter to the feedback message.

4.4.3.2. Typesafe Input

To check whether user input is of the correct type, you’ll have to add a TypeValidator to the field. A TypeValidator takes the class of the type which is required: Integer.class, Long.class etc. Usually you’d use the basic types from java.lang, because Wicket has already got the converters in place for those types. If you need more power, then you’d have to take a look at implementing your own IConverter.

public MyForm(String id, IModel model, IFeedback feedback) {
    super(id, model, feedback);
    TextField field = new TextField("integer", new PropertyModel(model, "integerField"));
    field.add(new TypeValidator(Integer.class));
    add(field);
}

As a shorthand, Wicket allows you to add the class of the property type to the field constructor. Wicket will then add a TypeValidator with the given type to the field.

public MyForm(String id, IModel model, IFeedback feedback) {
    super(id, model, feedback);
    TextField field = new TextField("integer",
            new PropertyModel(model, "integerField"), Integer.class);
    add(field);
}

Consequently, you’ll have to add a message to the properties file with the following name: component.path.TypeValidator (replace the component.path bit with your path to the field).

myForm.integer.TypeValidator=${input} is not a valid ${type}.

This component adds ${name}, ${input}, ${type}, ${exception}, ${locale} and ${format} as parameters to the error message interpolation. Format is only valid if the type conversion involves a date.

4.4.3.3. Range Checking

The IntegerValidator supplies you with the possibility to validate whether the user input lies within certain boundaries.

public MyForm(String id, IModel model, IFeedback feedback) {
    super(id, model, feedback);
    TextField field = new TextField("minmax",
            new PropertyModel(model, "integerField"));
    field.add(IntegerValidator.range(-100, 100));
    add(field);
}

The validator has the following parameters available in the error message interpolation: ${name}, ${input}, ${min} and ${max}.

myForm.minmax.IntegerValidator=${input} is not between ${min} and ${max}.

For your convenience, the IntegerValidator has some default validators at hand: IntegerValidator.INT ensures that the value is in the valid integer range, IntegerValidator.LONG ensures that the value is in the valid long range, IntegerValidator.POSITIVE_INT ensures that the value is equal or larger than 0 in the valid integer range, and finally IntegerValidator.POSITIVE_LONG does the same, but then for long values.

4.4.3.4. Length Validations

Ensuring that user input is of a certain length, or minimaly X or maximaly Y long can be done using the LengthValidator. The LengthValidator has three factory methods. min returns a minimal length validator, max gives you a maximum length validator and range returns a validator which checks whether the user input is at least min characters long and most max characters long.

public MyForm(String id, IModel model, IFeedback feedback) {
    super(id, model, feedback);
    TextField field = new TextField("text",
            new PropertyModel(model, "text"));
    field.add(LengthValidator.min(100));
    add(field);
}

The LengthValidator adds ${name}, ${input}, ${min} (when checking for a minimum length), ${max} (when checking for a maximum length) and ${length} (the actual length of the user’s input) to the error message parameterlist.

myForm.text.LengthValidator=${name} should contain between ${min} and ${max} characters

4.4.3.5. Pattern Validation

Sometimes it is needed to validate whether a user has filled in text that needs to comply with some pattern. For instance, the dutch zip code format is four digits followed by two uppercase letters, seperated by a space: 1234 AB. Wicket allows you to specify a PatternValidator using the full power of the java.util.regex regular expression package.

The constructor of PatternValidator takes either a regular expression string, or a precompiled regular expression.

public MyForm(String id, IModel model, IFeedback feedback) {
    super(id, model, feedback);
    TextField email = new TextField("zipcode",
            new PropertyModel(model, "zipcode"));
    field.add(new PatternValidator("\d\d\d\d [A-Z][A-Z]“));
    add(field);
}

The PatternValidator just adds ${name} and ${input} to the error message parameters.

myForm.zipcode.PatternValidator=${input} is not a valid zipcode

4.4.3.6. E-mail Address Validation

To validate e-mail addresses Wicket provides a special PatternValidator which uses a standard (albeit rather complex) regular expression for e-mail addresses. Instead of creating your own e-mail address validator, we advise you to use the EmailAddressPatternValidator as it is very easy to make a mistake in validating e-mail addresses.

public MyForm(String id, IModel model, IFeedback feedback) {
    super(id, model, feedback);
    TextField email = new TextField("email",
            new PropertyModel(model, "email"));
    field.add(EmailAddressPatternValidator.getInstance());
    add(field);
}

The EmailAddressPatternValidator just adds ${name} and ${input} to the error message parameters.

myForm.email.EmailAddressPatternValidator=${input} is not a valid e-mail address

Sourceforge, CVS, support

Wednesday, August 10th, 2005

Is it too much to take a look at the SourceForge Site Status page before you submit a support request with the sourceforge staff? I know that SourceForge has its weaknesses, but flooding the support staff with requests that could be answered easily with a quick glance at the status page show to me that users also have their weaknesses.

What triggered me to write this item is the current maintenance window for the CVS service of SourceForge.net site. It is currently impossible for developers to commit their work on the CVS services due to a hardware upgrade. They claim it has been scheduled, but probably only in their own agenda’s. Now the support queue is filling up with messages of users unable to connect to CVS and unwilling to read the Site Status page.

If they had announced this maintenance in a monthly newsletter, that would have saved you, me and themselves some extra work. At least it would have prevented this blog item.

Wicket Reference Manual Update

Monday, August 8th, 2005

I’ve begun work on a (long overdue) reference manual for Wicket, and wanted to get some initial feedback. Is this the kind of manual everybody is longing for?

PS. This is a direct paste from the generated DocBook version, so the markup is not ‘optimized’ for display within this JRoller template.

Chapter 4. Form Input

Abstract

This chapter shows how you can process input from users using forms, inputs and
other form related components. We show how to add validation to your fields and
give your users feedback when they entered wrong input.

4.1. Introduction

Many webapplications need some sort of user input. This is an integral part
of dynamic web applications. Many web applications don’t take localization and
internationalization into account. Often you have to write a lot of code for parsing
request parameters, validating and converting them into the actual types your
POJOs use.

With Wicket things will be different: you won’t have to write lots and lots of
scaffolding: Wicket takes care of a lot of things: updating your POJOs,
converting the user input taking localization into account, validating the input,
displaying internationalized messages when the input isn’t valid, etc.

4.2. Form Components

Most, if not all, Wicket form components will be discussed in the following sections. The
goal is not to be complete and show all possible uses of each component, but to give an
initial outline of how such a component can be used. For more information, please look in
the JavaDoc of the components.

4.2.1. Form

The
Form
component is a container for your form components. In the markup a form looks
like this:

To implement a form, subclass the
Form
, add FormComponents (such as CheckBoxes, ListChoices or TextFields) to the form
and override the
onSubmit
method. You can nest multiple buttons if you want to vary submit behaviour.
However, it is not necesary to use Wicket’s button class, just putting e.g.

suffices.

public class MyForm extends Form {
    public MyForm(String id, IModel model, IFeedback feedback) {
        // add (form) components
    }
    public void onSubmit() {
        // handle the submission of the form.
    }
    public void onError() {
        // do something special when an error occurs,
        // instead of displaying messages.
    }
}

Wicket will call onSubmit when the user input is
valid. When one or more child components of the form fails to validate,
Wicket will call onError. Wicket also supports
multiple buttons, which are discussed later.

4.2.2. TextField

A TextField receives user input in possibly its
most basic form: a single line of text. The markup for a
TextField component must be a

tag, otherwise Wicket
will throw an exception.

The markup for a textfield looks as follows:

In the Java code you can use several constructors for the component, depending
on the type of model you want to bind to the textfield.

public MyForm(String id, IModel model, IFeedback feedback) {
    super(id, model, feedback);
    add(new TextField("textField", new PropertyModel(model, "name")));
    ...
}

It is possible to use the true types of the fields in the textfield component.
Say that you need an integer value. Instead of performing the dataconversion
yourself, you specify for Wicket that you require an integer value by adding
an extra parameter to the TextField constructor: the
type of the property.

new TextField("integerField", new PropertyModel(model, "myInt"), Integer.class)

More information on this subject is provided in the validation section later on.

4.2.3. PasswordTextField

The PasswordTextField component is used for users to enter
their passwords. The field can be used in both login forms and registration forms.
In login forms it is usually required that the password is always cleared when the
page is rendered. When editing account information, this is not the case, so the
password field can be told not to clear the field when rendered. The markup looks
like this (the type="password" is required!):

The corresponding Java declaration looks like this:

PasswordTextField pwd = new PasswordTextField("pwd", new PropertyModel(model, "myPwd"));

When you want to use the field in a registration form, or some other form where the
password should not be reset on each render, you have to set the reset password flag
to false:

pwd.setResetPassword(false);

The default is to clear the field each time it is rendered.

4.2.4. TextArea

The TextArea component is a multi-line text editing component.
The component requires to be attached to a

The corresponding Java code looks like this:

TextArea area = new TextArea("myTextArea", new PropertyModel(model, "text"));

If you have to programmatically alter the rows or cols

attributes of the tag, then you can add AttributeModifiers
to the TextArea in order to produce the required effect:

area.add(new AttributeModifier("rows", 10));

4.2.5. CheckBox

The CheckBox component displays a checkbox. The checkbox can
either be checked or not, corresponding to a true or falseconstant>

value for the bound model. The CheckBox requires to be attached
to a input field whose type is ‘checkbox’:

The corresponding Java code:

CheckBox check = new CheckBox("myCheckbox", new PropertyModel(model, "boolValue"));

It is also possible to have the CheckBox respond directly to changes. Wicket will add
a small piece of JavaScript in order to generate the onSelectionChanged(Object newSelection)
event.

CheckBox check = new CheckBox("myCheckbox", new PropertyModel(model, "boolValue")) {
    protected boolean wantOnSelectionChangedNotifications() {
        return true;
    }
    protected void onSelectionChanged(Object newSelection) {
        Boolean value = (Boolean)newSelection;
        if(value.boolValue()) {
            // do something
        }
    }
};

4.2.6. RadioChoice

The RadioChoice component creates a number of radiobuttons
on your form. The RadioChoice requires both a model to bind the
value in, and a list of choices to display and select from. The list of choices can
come from a database or be filled from your Java code.
It requires an input markup tag of type ‘radio‘:

When you have a list filled with the strings ‘foo’ and ‘bar’, and you supply the
RadioChoice with that list, Wicket will generate each choice for you in the final
markup.

public MyForm(String id, IModel model, IFeedback feedback) {
    super(id, model, feedback);
    List choices = new ArrayList();
    choices.add("foo");
    choices.add("bar");
    add(new RadioChoice("myRadio", new PropertyModel(model, "foobar"), choices));
}

It is possible to construct more advanced methods of binding and creating selection
choices. See the chapter on database applications for more information.

4.2.7. ListChoice

This component shows a plain listbox filled with the choices to choose from. The
component only supports single selection values. When the number of choices is bigger than
the number of displayed values, a scrollbar is shown (by the browser). The required markup
looks like this:

The size attribute is merely for previewing purposes. Wicket will add the
attribute when it is not present. The Java code for creating a ListChoice:

public MyForm(String id, IModel model, IFeedback feedback) {
    List choices = new ArrayList();
    choices.add("foo");
    choices.add("bar");
    ListChoice lc = new ListChoice("myListChoice", new PropertyModel(model, "foobar"), choices);
    lc.setMaxRows(2);
    add(lc);
    ...
}

4.2.8. ListMultipleChoice

This component shows a plain listbox filled with the choices to choose from. The
component supports multiple selection values. When the number of choices is bigger than
the number of displayed values, a scrollbar is shown (by the browser). The required markup
looks like this:

The component needs a java.util.Collection as the model object,
in order to supply your object with the multiple choices. The Java code for this component
looks like:

public MyForm(String id, IModel model, IFeedback feedback) {
    List choices = new ArrayList();
    choices.add("foo");
    choices.add("bar");
    MultiListChoice lc = new MultiListChoice("myMultiListChoice", new PropertyModel(model, "foobarList"), choices);
    add(lc);
    ...
}

4.2.9. DropDownChoice

This component shows a dropdown box filled with the choices to choose from. The selected value
during rendering is the value of the model object. When the selection is changed, the selected
value is set on the model object. The required markup looks like this:

The corresponding Java code looks like:

public MyForm(String id, IModel model, IFeedback feedback) {
    List choices = new ArrayList();
    choices.add("foo");
    choices.add("bar");
    DropDownChoice lc = new DropDownChoice("myDropDownChoice", new PropertyModel(model, "foobar"), choices);
    add(lc);
    ...
}

The DropDownChoice also supports listening to
onchange events on the clientside, like the CheckBox
does. Wicket will add a small piece of JavaScript in order to generate the
onSelectionChanged(Object newSelection) event.

DropDownChoice choice = new DropDownChoice("myDropDownChoice", new PropertyModel(model, "foobar"), choices) {
    protected boolean wantOnSelectionChangedNotifications() {
        return true;
    }
    protected void onSelectionChanged(Object newSelection) {
        // do something
    }
};