You are viewing an old version of this page. View the current version.

Compare with Current View Page History

Version 1 Next »

This New User's Guide is a work in progress on a manual for Wicket. Using a wiki is a nice form for collaborative work on documentation. The contents will be converted later into docbook format in order to create a PDF and html documentation.

What is wicket

Wicket is one of the most recent in a long line of Java web development frameworks and stands on the shoulders of many that have come before it. Wicket is a component-based framework, which puts it in stark contrast to some of the earlier solutions to the sometimes monotonous task of web programming. Like other frameworks, Wicket builds on top of Sun’s servlet API; however, unlike frameworks like Struts or Spring MVC, the developer using Wicket is mostly removed from the request/response nature that is inherent with the web and Servlets. Instead of building controllers that must service many users and threads simultaneously, taking in requests, returning responses, and never storing any state, the Wicket developer thinks in terms of stateful components. Instead of creating a controller or action class, he or she creates a page, places components on it, and defines how each component reacts to user input.

This may all sound familiar to those with desktop GUI experience; Microsoft’s Visual Studio line, Sun’s Swing API, and Borland’s Delphi are all popular desktop GUI development tools that use component models. Using components allows the developer to spend less time on the visual tier of his or her app and more time implementing the core functionality. Even more important is how extensible this makes component-based GUIs. Adding additional functionality is simply a matter of adding one more component, which can act independently or in cooperation with other components in the view. These advantages have not been lost on web developers. In fact, many web framework projects have attempted to leverage the productivity and scalability of desktop applications. Apache Jakarta’s Tapestry and Microsoft’s own ASP.NET as well as Sun’s Java Server Faces specification all present solutions to component-based development over the web and bring new ideas to the table. All of these technologies separate the page layout into a template file. JSF uses Sun’s JSPs, ASP.NET uses ASP, and Tapestry use’s it’s own templating system based on standard HTML markup. These pages are rendered on each request, and as they are rendering, they make calls into a backing class to support dynamic content. As much as the word â€Å"templateâ€? would seem to suggest otherwise, this makes the page template king. Backing classes tends to be a series of listener methods, at the total mercy of the page template that is supposed to be merely defining the placement of components.

This works fine, and it is definitely a step up from a model 2 controller singleton class. Instead of a giant if block, we have well defined methods. Instead of being stateless, we can have instance variables. But now our Java code is a second-class citizen, existing merely to provide the page with the information it needs while it renders itself. Also, this backing class is always aware of the request-response cycle. It knows that getMember() is going to be called on every request, and reacts accordingly by getting a fresh copy from the database. Sure, the developer needs to deal with these details, but does it really have to be dealt with at the very top level of the application? Wicket allows the developer to build a page in Java (you remember Java right? It’s like OGNL, but with even more cool features) that uses and manipulates an HTML file, not the other way around. This page exists across requests, and does not even need to be aware of the request/response cycle. But something needs to know when a new request is starting and when the last one has finished rendering, right? All kinds of problems crop up when an object/relational mapper tries to work with an object from the last request, or the user is looking at an object that no longer represents what’s actually in the database, or when you merely try to store all that data in the session. The solution here is to not make the page aware of all the request details, but the data itself. That’s what Wicket tries to do.

So, what does it look like? Well, let us just get started with an example, and work our way from there.

My first application

The Wicket application we are going to develop is the ubiquitous 'Hello, World!' application. Simply put, we will create a web page using Wicket technology for printing the 'Hello, World!' string on a web page.
In the second release, some interactivity will be added to show how to do simple form related component development.

The goal is to generate the following markup:

<html>
<body>
Hello, world!
</body>
</html>

The HTML

Even though the requested result is so simple, there are many ways to achieve it. In this example we will use a rendering component called 'Label' to create the text 'Hello, World!'. So basically we have two things to consider:

  1. the html page
  2. the label component

The markup for the HTML page is the same as earlier:

<html>
<body>
Hello, world!
</body>
</html>

It is of course possible to add header information, apply style sheets, put javascript in there, etc. For the sake of the example, this is omitted.

Using this html-code is cheating, since we don't generate the required string, but have hard coded it in the html page.
In order to have Wicket render the text through a component, we need to tell Wicket which piece of the web page is a component. In this case we can replace the text with a label component definition.

<html>
{panel}
  <body>
    <span wicket:id="message">Message goes here!</span>
  </body>
{panel}
</html>

We have used the span element to markup the component and the wicket:id attribute to identify the component.

What we have accomplished until now is not enough to show the message in a web page. We have only told Wicket where to render the label component in the web page. In the next section we will show how to tell Wicket to render the message.

The Java code

In Wicket creating a web page consists of two tasks: creating the markup in which the components are defined and other information is shown, and creating Java classes to couple the web page to the required functionality. In the case of this example, we need to tell Wicket it needs to render the Label component. We also need to tell the label component to render the text 'Hello, World!'. In this section we will perform these steps one at a time.

First we need to create a web page. Wicket has a WebPage class suited for this task. All webpages need to be subclasses of WebPage. Another requirement is that the actual html file and the class name are equal: Index.html and Index, IndexPage.html and IndexPage or HelloWorld.html and HelloWorld. They also need to be in the same place on the classpath. The best way to develop is to put them in the same directory. This might seem strange in the beginning, especially when you are accustomed to separate html files and java files. However, since all pages are actually just components, it makes perfect sense in terms of reusability.

import wicket.markup.html.WebPage;
import wicket.markup.html.basic.Label;

public class HelloWorld extends WebPage
{
{panel}
  public HelloWorld()
  {
    add(new Label("message", "Hello World!"));
  }
{panel}
}

When you add components, you need to give them an id in the form of a string. In the above example, our component's id is 'message'. The id should be unique within it's own scope. In other words, no siblings are allowed with the same id.

When the markup is rendered, the id's of tags are matched against the component ids. Thus

<span wicket:id="message">Message goes here</span>

will look for a component with the id 'message' in the current scope.

Besides having an id, components also have a model. What the model is actually used for depends on the component. In this case, the model's contents (the string "Hello World!"), are used for the replacement of the body of the span tag. Models must implement wicket.model.IModel. There are a lot of components that have convenience constructors that construct a proper model for you. With labels, you can just provide a string, which is then wrapped into a simple model for the label to use.

Generally, you use models for the 'flexible' part of components, while it is best practice to keep your components immutable.

One more thing we need to get our example running is an Application object. You only need one for an application, and it can serve as a place to do the configuration for the application.

Our application could look like this:

package mypackage;

import wicket.protocol.http.WebApplication;

public class HelloWorldApplication extends WebApplication
{
{panel}
    public HelloWorldApplication()
    {
        getPages().setHomePage(HelloWorld.class);
    }
{panel}
}

NOTE: Beginning with release 1.2 the homepage is set by overriding getHomePage(). Therefore the above becomes:

package mypackage;

import wicket.protocol.http.WebApplication;

public class HelloWorldApplication extends WebApplication
{
{panel}
    public Class getHomePage()
    {
        return HelloWorld.class;
    }
{panel}
}

Sidenote: To see changes to template files immediatelly, overload the init() method of the WebApplication class by specifying that you are in development mode - remember to comment out in production:

{panel}
  // the second parameter is the path to your template files 
  // prefixed by wicket with the web root directory (e.g. /webapp)
  // (Default wicket configuration assumed)
  public void init() 
  {
    configure("development", "/");
    // Pre 1.2 getSettings().configure("development", "/");
  }
{panel}

The preferred version 1.2 way is to include the following snippet in your web.xml or
to use a system property -Dwicket.configuration

<context-param>
{panel}
  <param-name>configuration</param-name>
  <param-value>development</param-value>
{panel}
</context-param>

web.xml configuration

To load our application and have it available, we need to add the following lines to web.xml:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE web-app PUBLIC 
{panel}
   "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
   "http://java.sun.com/dtd/web-app_2_3.dtd">
{panel}

<web-app>

<context-param>
{panel}
  <param-name>configuration</param-name>
  <param-value>development</param-value>
{panel}
</context-param>

<servlet>
{panel}
  <servlet-name>HelloWorldApplication</servlet-name>
    <servlet-class>wicket.protocol.http.WicketServlet</servlet-class>
    <init-param>
      <param-name>applicationClassName</param-name>
      <param-value>mypackage.HelloWorldApplication</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
{panel}
</servlet>

<servlet-mapping>
{panel}
  <servlet-name>HelloWorldApplication</servlet-name>
  <url-pattern>/helloworld/*</url-pattern>
{panel}
</servlet-mapping>

</web-app>

And you are now ready to run your first Wicket app!

Deploying the application

One easy way of testing the application is by using Wicket QuickStart. Note that in the current release, some jar files from the jetty distribution were omitted: you need to add lib/org.mortbay.servlet.jar and ext/jasper-*.jar to your buildpath manually.

An interactive HelloWorld

The next thing we want to see is some interaction. Let us make the first example a little bit more dynamic.

We are going to extend our example to display an interactive message. We want the user to input what message should be
displayed, and use that input to render our label with.

The HTML

<html>
{panel}
  <body>
    &lt;span wicket:id="message"&gt;Message goes here&lt;/span&gt;
    <form wicket:id="messageInputForm">
    	<input type="text" wicket:id="messageInput"/>
    	<input type="submit" value="update"/>
    </form>
  </body>
{panel}
</html>

In the above markup you can see three Wicket components referenced: 'message', 'messageInputForm', and 'messageInput'. So, besides a label, we now have a form and input field.

The Java code

package mypackage;

import wicket.markup.html.WebPage;
import wicket.markup.html.basic.Label;
import wicket.markup.html.form.Form;
import wicket.markup.html.form.TextField;
import wicket.model.IModel;
import wicket.model.Model;

public class HelloWorld extends WebPage
{
{panel}
  public HelloWorld()
  {
    IModel messageModel = new Model("Hello World!");
    add(new Label("message", messageModel));
    add(new MessageForm("messageInputForm", messageModel));
  }
{panel}

{panel}
  private final class MessageForm extends Form
  {
    public MessageForm(String id, IModel model)
    {
      super(id);
      add(new TextField("messageInput", model));
    }
{panel}

{panel}
    protected void onSubmit()
    {
      // nothing to do here as the model is automatically updated
    }
  }
{panel}
}

The first thing you should notice is the nesting of components. The MessageForm is a sibling of the label, so it has to have a different id. The text field is a child of the MessageForm and thus has a different scoping. As the text field is set as a child of the form, it needs to be a nested tag in the form as well.

The next thing to notice is the use of a Model object. As said earlier, every Wicket component has a model. What a component uses its model for, depends on the component. A label uses its model to render the tag body, but a ListView expects a java.util.List as the model object, and loops through its elements. A model can be anything, as long as it implements wicket.model.IModel.

To process user input, you can use a Form. Forms update the models of their nested {{FormComponent}}s automatically. It does this by calling setObject(...) on the object with the input for that specific component. Hence, when a user pushes the submit button, the model of the text field is updated with the value that was in the HTML input text field. As, in this example, the label and the text field share the same model, when the model is updated via the text field, the label will render the new model object value as well.

More on models

Let us take a closer look at models.

The HelloWorld example program demonstrates the simplest model type in
Wicket:

public class HelloWorld extends WicketExamplePage
{
	public HelloWorld()
	{
		add(new Label("message", "Hello World!"));
	}
}

The first parameter to the Label component added in the constructor is
the Wicket id, which associates the Label with a tag in the
HelloWorld.html markup file:

<html>
{panel}
    <head>
{panel}
	<title>Wicket Examples - helloworld</title>
	<link rel="stylesheet" type="text/css" href="style.css"/>
{panel}
    </head>
    <body>
{panel}
	<span wicket:id="mainNavigation">main nav will be here</span>
	<span wicket:id="message">Message goes here</span>
{panel}
    </body>
{panel}
</html>

The second parameter to Label is the model for the Label, which
provides content which replaces any text inside the <span> tag that
the Label is attached to. The model being passed to the Label
constructor above is apparently a String. But if we look inside the
Label constructor, we see that this is merely a convenience and that
we see that this constructor is merely there for convenience, and that
the Label constructor wraps its String argument in a Model object like
this:

public Label(final String id, String label)
{
{panel}
  this(id, new Model(label));
{panel}
}

If we look up the inheritance hierarchy for Label, we see that Label
extends WebComponent, which in turn extends Component. Each of these
superclasses has only two constructors. One Component constructor
takes a String id:

public Component(final String id)
{
{panel}
  setId(id);
{panel}
}

And the other takes a String id and an IModel:

public Component(final String id, final IModel model)
{
{panel}
  setId(id);
  setModel(model);
{panel}
}

IModel is the interface that must be implemented by all Wicket model
objects. It looks like this:

public interface IModel extends IDetachable
{
{panel}
  public Object getNestedModel();
  public Object getObject(final Component component);
  public void setObject(final Component component, final Object object);
{panel}
}

And the base interface IDetachable looks like this:

public interface IDetachable extends Serializable
{
{panel}
  public void detach();
{panel}
}

These details are not especially interesting to a beginning model
user, so we will come back to this later. What we need to know right
now is that Model extends AbstractModel, which implements IModel. So a
Model is an IModel and therefore it can be passed to the
Component(String, IModel) constructor we saw a moment ago.

If we take a peek inside Model, we'll see that the Model object is
simply a wrapper that holds a Serializable object:

  private Serializable object;

Model's object value is Serializable in order to support deployment of
web applications in clustered environments. Note also that since

IModel extends IDetachable, which extends Serializable, all IModel
wrapper classes are themselves Serializable. So all Wicket models are
therefore serializable, which means that they can be replicated
between servers in a cluster. Don't worry if you don't fully
understand this. We will talk more about clustering later.

Working with POJOs

While using a String like we did in the above example ('Hello World') is convenient, you will usually want to work with domain objects directly. To illustrate how Wicket supports working with domain object, we use the following 'Plain Old Java Object' for our examples:

import java.util.Date;

public class Person
{
	private String name;
	private Date birthday;

	public Person()
	{
	}
	public String getName()
	{
		return name;
	}
	public void setName(String name)
	{
		this.name = name;
	}
	public Date getBirthday()
	{
		return birthday;
	}
	public void setBirthday(Date birthday)
	{
		this.birthday = birthday;
	}
}

Static models

Like we have seen above, the simplest way of providing e.g. a Label a model, is just to provide a string, and let the Label implicitly construct one for you.

add(new Label("name", person.getName()));

We can create the model explicitly like:

Model model = new Model(person.getName());
add(new Label("name", model));

This has the same effect as the first example, but as we now have the reference to the model, we can use it e.g. to share it with other components like we did in our little interactive example earlier.

Using models like this works fine as long as there are no changes in the underlying data that should be displayed. You could call these models 'static' or 'push' models, as you have to synchronize any data changes to the model itself.

Dynamic models

While static models are the easiest to use, it is often a good idea to let your models get their current objects dynamically from some source so that you can be certain that they display the most recent value. You could call these models 'dynamic' or 'pull' models.

Property models

The PropertyModel class allows you to create a model that accesses a
particular property of its nested model object at runtime. This
property is accessed using an expression language called OGNL (see
http://www.ognl.org) (as of version 1.2, OGNL has been replaced by an internal implementation). The simplest PropertyModel constructor is:

public PropertyModel(final Object modelObject, final String expression)

which takes a model object and an OGNL expression. When the property model
is asked for its value by the framework, it will use the OGNL expression to
access the model object's property.

Looking at our example POJO, the OGNL expression "name" can be used to access the "name" property of any Person object via the getName() getter method. Also, when updating a model, using OGNL expression "name" has the effect of calling setName(String). Hence construct a property model to use our POJO, give it Ognl expression "name" and set it on a textfield, not only will that textfield display the current value of the "name" property, it will also update the "name" property with any user input provided.

More complex OGNL expressions are possible as well. For example, you can access sub-properties via reflection using a dotted path notation, which means the OGNL expression "person.name" is equivalent to calling getPerson().getName() on the given model object. Arrays can be accessed as in "persons4.name" and OGNL even supports method calls such as "person.getDescription(true)". As you can see, PropertyModels are quite a powerful way to give Wicket components access to model objects.

A second contructor on PropertyModel is available for models that wish to access properties involving type conversions:

public PropertyModel(final Object modelObject, final String expression, Class propertyType)

Although OGNL will do automatic type conversions for you, it may not always do the kind of conversion you desire. This alternative constructor creates a property model that forces a particular conversion to occur. For example, you may wish to access a String or Object property of something as an Integer. Constructing a PropertyModel with new PropertyModel(object, "myString", Integer.class) would force the property to be converted to and from an Integer on get/set operations.

Compound property models

If you have looked at some examples of Wicket already, you may have wondered why components, which generally must have a model, can be constructed with
only an id, omitting any model. There are three reasons for this.

The first, most obvious reason is that not all components actually need a model. Panels and pages, for example, do not use models, though you might find it handy to store a model
in these components.

The second reason to construct a Component with no model is that it is
sometimes impossible to have a model ready for the call to
super(String, IModel) in the Component's constructor. In this case,
the Component can be constructed without a model, and the model can
be later set with a call to setModel().

The third reason to construct a component with no model is that some
components are actually bound to their models at runtime. When an
attempt is made to retrieve the model for a Component which does not
yet have one, instead of failing and returning null, the getModel()
method in Component calls the method initModel(), which gives the Component
an opportunity to lazy-initialize, returning a model on-the-fly.

This mechanism opens up all kinds of possibilities for model
initialization. One particularly convenient and efficient lazy
model initialization strategy is employed by the CompoundPropertyModel
and BoundCompoundPropertyModel classes to allow containers to share
their models with children. By sharing model objects like this, fewer
objects are created, which saves memory, but more importantly, it
makes replication of models much cheaper in a clustered environment.

To use a CompoundPropertyModel, you simply set one as the model for
any container. However, a very typical place to install a
CompoundPropertyModel is on a Form or Page. This is natural, because
the compound model itself is usually the model that is being displayed
by the Page or edited by the Form.

To see a CompoundPropertyModel in action, take a look at the FormInput
example. In the InputForm nested class in FormInput.java, the Form
is constructed like this:

public InputForm(String name, IFeedback feedback)
{
{panel}
  super(name, new CompoundPropertyModel(new FormInputModel()), feedback);
  ...
{panel}
}

If we look at the next few lines of the Form's constructor, we see
statements like:

add(new RequiredTextField("stringProperty"));
add(new RequiredTextField("integerProperty", Integer.class));
add(new RequiredTextField("doubleProperty", Double.class));

these statements are adding FormComponents to the Form. But they are
not explicitly attached to any model. Instead, they will inherit the
CompoundPropertyModel for the form at runtime. When the framework needs
the model for a RequiredTextField, it will call getModelObjectAsString().
This method retrieves the text field's model by calling getModel(), which
is implemented like this:

public IModel getModel()
{
{panel}
  if (model == null)
  {
    this.model = initModel();
  }
  return model;
{panel}
}

Since the RequiredTextField has no model, the initModel() method will
be called, resulting in a search up the containment hierarchy for a
CompoundPropertyModel that can be inherited by the model-less child:

protected IModel initModel()
{
{panel}
  for (Component current = getParent(); current != null; current = current.getParent())
  {
    final IModel model = current.getModel();
    if (model instanceof CompoundPropertyModel)
    {
      return model;
    }
  }
  return null;
{panel}
}

The text field will discover the CompoundPropertyModel for the Form
and set that as its own model. So getModel() on the text field
ultimately returns the model of the Form.

Next, the nested model object is retrieved from the model by passing
in the Component (in this case the RequiredTextField) as a parameter
to IModel.getObject(Component). This is the magic that allows the
CompoundPropertyModel to retrieve the right value from the Form's
model for the Component that is asking for it:

final Object modelObject = model.getObject(this);

The retrieval is done by using the name of the Component as the OGNL
expression to access the model. In the case of this component

add(new RequiredTextField("stringProperty"));

the getStringProperty() method would be called on the Form's model.

The model's object value is available in this way to the component for
processing. In the case of the stringProperty text field component, it
will convert the value to a String. In the case of other
RequiredTextFields in the FormInput form, a conversion may occur based
on the third parameter to the Component. For example, this component:

add(new RequiredTextField("integerProperty", Integer.class));

will convert the contents of the text field to and from an Integer
value.

In the event that you need more flexibility or OGNL power in your
compound models, you can use the BoundCompoundPropertyModel. This
class provides three methods you can call on the container's model
object to bind a given child Component to a specific OGNL property
and/or type conversion:

public Component bind(final Component component, final String ognlExpression)
public Component bind(final Component component, final Class type)
public Component bind(final Component component, final String ognlExpression, final Class type)

To see how this might be used, suppose that the stringProperty value
needed to be bound to the OGNL expression "person0.stringProperty".
In the FormInput constructor, we'd say something like this:

super(name, feedback);
final BoundCompoundPropertyModel formModel = new BoundCompoundPropertyModel(new FormInputModel());
setModel(formModel);
add(formModel.bind(new RequiredTextField("stringProperty"), "person[0].stringProperty"));

The Form is constructed without a model. We then create the Form's
model as a BoundCompoundPropertyModel, set it as the Form's model and
finally use it to bind the RequiredTextField to the desired OGNL
expression.

String Resource Models

Localization of resources in Wicket is supported by the Localizer
class. This provides a very convenient way to retrieve and format application
and component specific resources according to the Locale that the
user's Session is running under. In many cases, it will be sufficient
to simply retrieve a localized String in this way, but if a formatted, localized
string is desired as a model, a StringResourceModel may be used.
StringResourceModels have a resource key (for looking up the string
resource in a property file), a Component, an optional model and an
optional array of parameters that can be passed to the Java
MessageFormat facility. The constructors look like this:

public StringResourceModel(final String resourceKey, final Component component, 
{panel}
                           final IModel model)
{panel}

public StringResourceModel(final String resourceKey, final Component component, 
{panel}
                           final IModel model, final Object[] parameters)
{panel}

A very simple example of a StringResourceModel might be a Label
constructed like this:

add(new Label("greetings", new StringResourceModel("label.greetings", this, null)));

where the resource bundle for the page contains an entry like this:

label.greetings=Welcome!

By adding a model, we can use OGNL to interpolate properties from the
model into the localized string in the resource bundle. For example,
suppose we wanted to add the name from a User object to the greeting
above. We'd say:

User user;

...

add(new Label("greetings", new StringResourceModel("label.greetings", this, user)));

and have a resource like:

label.greetings=Welcome, ${user.name}!

where User has a getName() method exposing its "name" property.

Custom models

If we do not want to use Ognl/ introspection, but instead want to to pull a fresh value from the model on each request in a more strongly typed manner, we could provide our own implementation of IModel:

final Person person = new Person();
person.setName("Fritzl");
Model model = new Model()
{
	public Object getObject(wicket.Component component)
	{
		return person.getName();
	}
};
add(new Label("name", model));

Note that in the above example, we extended from Model instead of implementing IModel directly, and we did not bother writing setObject (as for the label it is not needed).

By implementing your own models, you can support any kind of model behaviour you can think of, though it is usually a more verbose way of doing things.

Detachable Models

If you look at the inheritance hierarchy for types that implement
IModel in the Wicket core, you will notice that there are two root
classes which implement IModel directly: AbstractModel and
AbstractDetachableModel. AbstractModel is intended as a base class
for all models which do not make use of IModel's IDetachable
interface. To remove the need to implement IModel.IDetachable.detach,
AbstractModel looks like this:

public abstract class AbstractModel implements IModel
{
{panel}
  public void detach()
  {
  }
{panel}
}

AbstractModel has a single subclass, Model, which we talked about at
the beginning of this article, which wraps a Serializable object.

All other model classes in Wicket are "detachable" and extend the base
class AbstractDetachableModel. A detachable model in Wicket is a model
which can get rid of a large portion of its state to reduce the amount
of memory it takes up and to make it cheaper to serialize when
replicating it in a clustered environment. When an object is in the
detached state, it contains only some very minimal non-transient state
such as an object id that can be used to reconstitute the object from
a persistent data store. When a detached object is attached, some
logic in the object uses this minimal state to reconstruct the full
state of the object. This typically involves restoring fields from
persistent storage using a database persistence technology such as JDO
or Hibernate.

To make implementation of detachable models easy,
AbstractDetachableModel provides some basic inheritable logic for
attaching and detaching models. The basis for this logic is a
transient boolean field which is true when the object is in the
attached state and false when it is in the detached state:

private transient boolean attached = false;

Which state a detachable object is in is available via:

public boolean isAttached()
{
{panel}
  return attached;
{panel}
}

Two methods, attach() and detach() (which implements the IDetachable
interface contract), use this boolean to call the abstract subclass
methods onAttach() and onDetach() only when required:

public final void attach()
{
{panel}
  if (!attached)
  {
    attached = true;
    onAttach();
  }
{panel}
}

public final void detach()
{
{panel}
  if (attached)
  {
    attached = false;
    onDetach();
  }
{panel}
}

protected abstract void onAttach();

protected abstract void onDetach();

The implementations of IModel.getObject(Component) and
IModel.setObject(Component) automatically call attach()
before delegating responsibility to abstract methods:

public final Object getObject(final Component component)
{
	attach();
	return onGetObject(component);
}

public final void setObject(final Component component, final Object object)
{
	attach();
	onSetObject(component, object);
}

protected abstract Object onGetObject(final Component component);

protected abstract void onSetObject(final Component component, final Object object);

All of this very neatly encapsulates what it means to be a detachable
object in Wicket. If you implement these abstract methods:

public abstract Object getNestedModel();
protected abstract void onAttach();
protected abstract void onDetach();
protected abstract Object onGetObject(final Component component);
protected abstract void onSetObject(final Component component, final Object object);

you will immediately have a functioning detachable model that shrinks
and then restores its state when replicated in a cluster.

There are two sub-types of AbstractDetachableModels. The first is
AbstractPropertyModel and the second is
AbstractReadOnlyDetachableModel. The latter is very simple and just
adds this override to AbstractDetachableModel:

protected final void onSetObject(final Component component, final Object object)
{
{panel}
     throw new UnsupportedOperationException("Model " + getClass() + 
                                             " does not support setObject(Object)");
{panel}
}

The StringResourceModel we talked about above is an
AbstractReadOnlyDetachableModel since resource strings are read-only
in nature.

AbstractPropertyModel provides implementation details for the
PropertyModel, CompoundPropertyModel and BoundCompoundPropertyModel
classes we discussed above by implementing onGetObject() and
onSetObject() using an OGNL expression and conversion type retrieved
from a subclass via abstract methods ognlExpression() and
propertyType(). The simple PropertyModel class just returns the OGNL
expression and type it was constructed with:

protected String ognlExpression(Component component)
{
	return expression;
}

protected Class propertyType(Component component)
{
	return propertyType;
}

While CompoundPropertyModel returns the name of the component as its
OGNL expression:

protected String ognlExpression(final Component component)
{
	return component.getId();
}

protected Class propertyType(final Component component)
{
	return null;
}

Finally, BoundCompoundPropertyModel stores a set of bindings internally
and returns the OGNL expression for a component based on this information:

protected String ognlExpression(final Component component)
{
	final Binding binding = getBinding(component);
	return binding != null ? binding.ognlExpression : component.getId();
}

protected Class propertyType(final Component component)
{
	final Binding binding = getBinding(component);
	return binding != null ? binding.type : null;
}

LoadableDetachableModel

A model that makes working with custom detachable models a breeze is LoadableDetachableModel. LoadableDetachableModel holds a temporary, transient model object, that is set on attaching by calling abstract method 'load', and that will be reset/set to null on detaching.

In the following example, we load objects (venues) on attachement.

LoadableDetachableModel venueListModel = new LoadableDetachableModel()
{
{panel}
  protected Object load()
  {
     return getVenueDao().findVenues();
  }	
{panel}
};

During the handling of the request cycle, the list of venues we found by calling 'findVenues' is returned when getObject is called on the venueListModel. When detached, the model representation is cleaned up.

Special purpose models

Some components need specialized models for their workings. Or, as is the case with components that inherit from AbstractChoice, they need more than one model. Currently, these specialized models are IChoiceList and FileUpload. You can find information on them in the JavaDocs of the components that use them, or you can take a look at the examples.

Custom components

You already have seen some Wicket components in action. You also learned that you can influence what the components actually do by providing them with proper models. Now it is time to look at how to customize Wicket components.

Extending

Usually you do not want to start from scratch when you customize a component. Most components can be extended, and have methods that are explicitly meant for customization.

Some components do not even work without this, like wicket.markup.html.link.Link, which has abstract method onClick, or wicket.markup.html.list.ListView that has abstract method populateItem.

Component wicket.markup.html.form.DropDownChoice is a non-abstract component, but by extending it, we can alter its behaviour. For example, look at:

add(new DropDownChoice("venueSelect", 
{panel}
                        new PropertyModel(this, "currentVenue"), getVenueDao().findVenues())
{panel}
{
{panel}
  protected boolean wantOnSelectionChangedNotifications()
  {
    return true;
  }
{panel}
});

By overloading method wantOnSelectionChangedNotifications, and have it return true (instead of false which is the default), an onchange javascript event handler will be generated, so that on each new selection of the dropdown, a roundtrip will be made to the server, updating the model of the dropdown component. And if you used your models smart enough, this can have the effect that other components have an updated rendering as well.

And if we want to customize the component even further, we could do:

add(new DropDownChoice("venueSelect",
{panel}
                       new PropertyModel(this, "currentVenue"), getVenueDao().findVenues())
{panel}
{
{panel}
  protected boolean wantOnSelectionChangedNotifications()
  {
    return true;
  }
{panel}

{panel}
  protected void onSelectionChanged(Object newSelection)
  {
    // do something here...
  }
{panel}
});

and do something nice in the ''onSelectionChanged// event handler.

By making use of models that use e.g. a shared property, we can do all kinds of neat things. Here is an example:

add(new DropDownChoice("venueSelect", 
{panel}
                       new PropertyModel(this, "currentVenue"), getVenueDao().findVenues())
{panel}
{
{panel}
  protected boolean wantOnSelectionChangedNotifications()
  {
    return true;
  }
{panel}
});
WebMarkupContainer container = new WebMarkupContainer("rolesListContainer")
{
{panel}
  public boolean isVisible()
  {
    return getCurrentVenue() != null;
  }
{panel}
};
add(container);

Note that we fed our dropdown with a property model that works on this (e.g. a Page) using property 'currentVenue'.
Now, with the second component we override method isVisible, and use that same property 'currentVenue' for our evaluation.
If any venue is selected, we'll display the container and anything that is nested on it. If no venue is selected, we do not
display anything. This is a very handy trick to switch parts of your page on and off, and as the dropdown will generate a
roundtrip on each selection, our page will feel very dynamic.

TODO... write more

AttributeModifiers

TODO

Panels and Borders

See also Panels_and_borders

Both Panels and Borders have their own markup file, but the markup is used in different ways:

The Border component inserts markup before and after its child components.

{panel}
   <html>
    <body>
     <div wicket:id="myBorder">
      <!-- Border markup -->
      <span wicket:id="myContent">content</span>
      <!-- Border markup -->
     </div>
    </body>
   </html>
{panel}

The Panel component inserts markup into the body of the tag.

{panel}
   <html>
    <body>
     <div wicket:id="myPanel">
      <!-- Panel markup -->
     </div>
    </body>
   </html>
{panel}

See Panel for more information.

Doing it (almost) from scratch

TODO

Using Forms

TODO

Start with an example using the pojo from 4

Subclass wicket.markup.html.WebPage and in the constructor initialize and add the required Form implementation.

public class EditCustomerPage extends WebPage {
{panel}
    public EditCustomerPage() {
        add(new CustomerForm("customerForm", new Customer()));
    }
{panel}
}

Subclass wicket.markup.html.form.Form and in the constructor add the necessary form elements.
These will be bound to the individual html form elements through the wicket:id attributes.

public class CustomerForm extends Form {
{panel}
    public CustomerForm(String name, Customer customer) {
        super(id, new CompoundPropertyModel(customer));
        add(new TextField("name"));
    }
{panel}
}

The html form itself must contain a wicket:id attribute that matches the Form added to the WebPage. Each form element must also have a corresponding wicket:id to each FormComponent added to the Form. In this example the form is bound to the "customerForm" Form instance and the text input is bound to the "name" TextField. There is also a single submit button that is not bound to any component. Wicket automatically provides the submission handling functionality through the Form base class implementation. Button components only need to be added to the Form if multiple buttons are required.

<form wicket:id="customerForm">
{panel}
    name: <input type="text" wicket:id="name"/><br>
    <input type="submit"/>
{panel}
</form>

Updating the model

What happens when the form is submitted? Describe how the automatic updating of pojo's when
property models are used. Describe how to use buttons and a button-less form.

Validation

<em>NO LONGER VALID AS OF RC1, FORM parent method doesn't take a FeedbackPanel</em>

Describe how validation works and how to implement custom validation. Also give a short explanation of how to display messages.

Adding RequiredValidator to a form element will allow only non-null and non-empty values to pass validation successfully.

public CustomerForm(String name, Customer customer, IFeedback feedback) {
{panel}
    super(id, new CompoundPropertyModel(customer), feedback);
    add(new TextField("name").add(RequiredValidator.getInstance()));
{panel}
}

For convenience the class RequiredTextField is provided. This TextField automatically includes a RequiredValidator.

public CustomerForm(String name, Customer customer, IFeedback feedback) {
{panel}
    super(id, new CompoundPropertyModel(customer), feedback);
    add(new RequiredTextField("name"));
{panel}
}

To provide validation feedback a FeedbackPanel can be instantiated. This should be added to the page (for display) and associated with the form by passing it into the form constructor.

public EditCustomerPage() {
{panel}
    FeedbackPanel feedback = new FeedbackPanel("feedback");
    add(feedback);
    add(new CustomerForm("customerForm", new Customer(), feedback));
{panel}
}

The FeedbackPanel can then be added to the html with a wicket:id span.

<span wicket:id="feedback">feedback will be here</span>

Finally, create a .properties file in the same directory as your html template and class file using the same naming conventions. In this case it would be called EditCustomerPage.properties. Use this file to define the error messages for each input in the form.

formId.inputId.ValidatorClassName=Your custom message.

Conversion

Describe how conversion works (when using property models) and how to implement custom conversion.

Form components

Give a list with a short description of the form components that are available in core.

Life cycle

Describe the life cycle of Wicket apps, sessions and requests.

Custom Sessions

The wicket way of storing objects in your session is by extending the
wicket session. For example if you want to store some kind of user
object in your session, you would create a getter and setter for it in
your custom wicket session:

Add the property to your custom Session object.

public class MySession extends WebSession {
{panel}
   public MySession(WebApplication application) {
      super(application);
   }
   private String myAttribute;
   // ... getters and setters
{panel}
}

and override either of the following methods on your Application class:

{panel}
   protected ISessionFactory getSessionFactory() {
       return this.sessionFactory;
   }
   public Session newSession() {
       return new MySession(WebApplication.this);
   } 
{panel}

Custom RequestCycles

Describe how to use custom request cycles.

Listeners

Describe the IRequestListener, and how the ILinkListener and IOnChangeListener interfaces were implemented. This chapter will give users a better, in-depth understanding of Wicket's workings.

Localization and Skinning of Applications

Wicket provides a wide range of features that make it possible to easily create web applications for different locales and with different skins (styles). First, lets take a look at the basic localization and skinning features of Wicket. After that we will move on to how you can extend this functionality to take full control over localization.

Locale and Style

Wicket will use the locale of the incoming request along with a Style identifier to load resources. These resources include

*Markup files
*localization resource bundles (properties files)
*form input validators (also properties files)

Locale is set in the Wicket WebRequest object from the http request header locale in the User Agent field. Optionally, a user's locale can be set in their Session object by calling setLocale.

Style enables skinning of the application and is set by calling setStyle on the Wicket Session object. Session.get() returns the Session object associated with the current request.

Additionally, classes derived from Component provide a getVariation method which the developer can override on a per component basis to further discriminate resources to load.

Markup Files

Describe the loading of markup files by locale and style.

The ResourceStreamLoader determines what markup file to load for a component based on the variant, style, and locale values set for that component.

The Pub example in wicket-examples demonstrates how html markup is chosen based on locale. There is a default Home.html, Home_de_DE.html for users with German locale set, Home_zh_CN.html for Mandarin, etc.

These pages can be skinned by setting the Style attribute in the user's session. You could have three different styles for home: stone, wood, and brick. If the style you set does not have a corresponding markup file, then the localized markup is returned. If there is no markup for the locale, the default markup is returned. You can skin the Home page for a German user by providing Home_stone_de_DE.html, Home_wood_de_DE.html, and Home_brick_de_DE.html.

There is also a variation attribute that is additive to the style attribute. If no style attribute has been set, then variation takes the place of style in the resource name. If style is set, variation + "_" is prepended to the style name, which is then returned by getStyle().

If you have a panel inside Home called kitchen, you can override getVariation in the kitchen panel to return "granite" or "corriander". For a German locale, you could provide the following markups for the granite variation: Kitchen_granite_de_DE.html, Kitchen_granite_stone_de_DE.html, Kitchen_granite_wood_de_DE.html, Kitchen_granite_brick_de_DE.html. The possibilities are exponential.

The javadoc for the Wicket Session class describes the algorithm for resolving markup resources to load:

String Resources

Wicket can also manage message localization with ResourceBundle properties files.

The Localizer is a utility class that encapsulates all of the localization related functionality in Wicket so it can be accessed by all areas of the framework in a consistent way. All classes derived from Component have a getLocalizer() method which retrieves the shared Localizer from the Application. The Localizer maintains a static cache of messages already retrieved by a key generated from the class, locale, style and messageKey for the message. Message bundles are looked up using classes derived from AbstractStringResourceLoader. The Localizer fetches a list of AbstractStringResourceLoader from the Application object. By default, the Application provides a ComponentStringResourceLoader and an ApplicationStringResourceLoader.

In the default setup, the ComponentStringResourceLoader is first asked to locate the message bundle. If it can't find one (using the algorithm described below), the ApplicationStringResourceLoader is consulted next. The ApplicationStringResourceLoader attempts to find a single resource bundle that has the same name and location as the application

The algorithm employed by ComponentStringResourceLoader to resolve message requests is described in the javadoc for the AbstractStringResourceLoader:

The component based string resource loader attempts to find the resource from a bundle that corresponds to the supplied component object or one of its parent containers. Generally the component will be an instance of Page, but it may also be an instance of any reusable component that is packaged along with its own resource files. If the component is not an instance of Page then it must be a component that has already been added to a page.

The search order for resources is built around the containers that hold the component (if it is not a page). Consider a Page that contains a Panel that contains a Label. If we pass the Label as the component then resource loading will first look for the resource against the page, then against the panel and finally against the label.

An exception will be thrown if you are using Localizer on a component that has not already been added to a page. Unless you are sure your component has already been attached to the Page hierarchy, use StringResourceModel, which will defer message bundle lookup until after the component has been attached to a page (during the render process).

The naming convention for resource lookup is the similar to the convention to markup files. The resource loader is style and locale aware. For example, you have a page Home with a panel Kitchen that has a panel Sink, and Sink has labels LeftFawcett (key fawcett.left) and RightFawcett (key fawcett.right) that need to be localized. Your locale is German and your style is "standard". The ComponentStringResourceLoader will first look for fawcett.left and fawcett.right in Home_standard_de_DE.properties, then the same extension for Kitchen, and then Sink. If the key is not found, it will continue following the same steps detailed above for the markup files, but for each step trying it for Home, then Kitchen, then Sink

The Localizer contains powerful ognl string substitution methods for manipulating message values. Examples are provided in the javadoc for StringResourceModel, such this:

/**
{panel}
 * In this example the found resource string contains an OGNL expression that is  
 * substituted via the model.
 */  
{panel}
public MyPage extends WebPage 
{
{panel}
   public MyPage(final PageParameters parameters) 
   {
       WeatherStation ws = new WeatherStation();
       add(new Label("weatherMessage",
                     new StringResourceModel("weather.message", 
                                             this, new Model(ws)));
   }
{panel}
}

Where the resource bundle contains the entry

weather.message=Weather station reports that the temperature is ${currentTemperature} ${units}

For Localizing components, you mostly will want to rely on StringResourceModel. As mentioned before, you cannot call getLocalizer on a component before it has been attached to the framework (added to a hierarchy that has a Page). StringResourceModel uses Localizer inside it, but does not get rendered until after the component heirarchy has been established, so no exceptions. The StringResourceModel offers all the features of Localizer, plus the application of substitution parameters by java.text.MessageFormat. Again, there is an example demonstrating this in the StringResourceModel javadocs:

 
public MyPage extends WebPage 
{
{panel}
   public MyPage(final PageParameters parameters) 
   {
       WeatherStation ws = new WeatherStation();
       Model model = new Model(ws);
       add(new Label("weatherMessage",
                 new StringResourceModel(
                     "weather.detail", this, model,
                     new Object[] 
                     {
                         new Date(),
                         new PropertyModel(model, "currentStatus"),
                         new PropertyModel(model, "currentTemperature"),
                         new PropertyModel(model, "units")
                     }));
   }
{panel}
}

And where the resource bundle entry is:

weather.detail=The report for {0,date}, shows the temparature as {2,number,###.##} {3} \
{panel}
                       and the weather to be {1}  
{panel}

FormValidators derived from AbstractValidator or StringValidator also exploit Wicket's localization capabilities. Inside, they delegate localization to the Localizer. There must be a resource bundle properties file in the Localizer search path that has a messageKey equivalent to form-name.component-name.validator-class. This allows the validators to be Style and locale aware. OGNL substitution is enabled, but parameterized MessageFormat is not.

Other Resources

Describe the loading of other resources by locale and style.

String Resource Loaders

Describe how to write new string resource loaders.

Scalability and Session Management

Write about the following:

  • How session attributes are managed
  • How to control what end up in the session
  • Future directions
  • No labels