This Confluence has been LDAP enabled, if you are an ASF Committer, please use your LDAP Credentials to login. Any problems file an INFRA jira ticket please.

Child pages
  • Lifecycle of a Wicket Application
Skip to end of metadata
Go to start of metadata

Bookmarkable link

Table of contents

The Life-Cycle of a Wicket Application

Loading the Application

A Wicket application runs in any J2EE compliant application server by defining a Java filter in the application's web.xml file:

<?xml version="1.0" encoding="ISO-8859-1"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
	version="2.5">

	<display-name>wicketproject</display-name>

	<!--
		There are three means to configure Wickets configuration mode and they 
		are tested in the order given.
		
		1) A system property: -Dwicket.configuration 
		2) servlet specific <init-param> 
		3) context specific <context-param>

		The value might be either "development" (reloading when templates change) or 
		"deployment". If no configuration is found, "development" is the default. -->

	<filter>
		<filter-name>wicket.wicketproject</filter-name>
		<filter-class>org.apache.wicket.protocol.http.WicketFilter</filter-class>
		<init-param>
			<param-name>applicationClassName</param-name>
			<param-value>com.yourcompany.WicketApplication</param-value>
		</init-param>
	</filter>

	<filter-mapping>
		<filter-name>wicket.wicketproject</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>
</web-app>

The filter class specified will always be "org.apache.wicket.protocol.http.WicketFilter". The "applicationClassName" init-param provided must be the name of a WebApplication subclass. In the case above, it is "com.yourcompany.WicketApplication".

When WicketFilter is loaded, it will use this information to instantiate a single instance of your application class.

Servicing a Request

The following steps occur each time that WicketFilter intercepts a request and a redirect is not required:

  1. it sets the application to the thread context
  2. the application creates a WebRequest, WebResponse and RequestCycle
  3. the RequestCycle's processRequestAndDetach() method is called to handle the request

How RequestCycle Handles a Request

For each request, a RequestCycle object does the following 3 things:

  1. Calls the overridable method onBeginRequest() to allow RequestCycle subclasses to do things at the beginning of each request, such as opening a Hibernate session.
  2. Resolves the IRequestHandler to handle the request.
  3. Calls any listeners to onRequestHandlerResolved
  4. Calls requestHandlerExecutor.execute(handler); which in turn calls IRequestHandler.respond(). See API for a list of implementations.
  5. Calls any listeners to onRequestHandlerExecuted
  6. Calls the overridable method onEndRequest() to allow RequestCycle subclasses to do things at the end of each request, such as closing a Hibernate session.

Step 3 may involve some pretty sophisticated logic. When a request URL is parsed, it may include information such as a Component listener to invoke. This Component listener may create a whole new Page that is used.

Clustering

When a Page is replicated from one machine in a cluster to another, the onSessionAttach() method will be called for every component on the Page.

Model Changes

When models or model values are changed in Wicket by a call to setModel() or setModelObject(), the change results in a call to onModelChanging() before the change actually occurs and then onModelChanged() after the change occurs.

Because Wicket cannot always know if a model has changed, you can help it to do smart things (such as versioning your Page's model changes)
by calling modelChanging() before altering a Component's model object and modelChanged() afterwards. For example, if your component has a
Model that wraps a List object, there is no way for Wicket to know if you set the 3rd element to some new value. By calling modelChanging() and modelChanged(), you can ensure that Wicket knows about your change.

Rendering

A Page renders itself by rendering its associated markup (the html file that sits next to the Page). As MarkupContainer (the superclass for Page) iterates through the markup stream for the associated markup, it looks up components attached to the tags in the markup by id. Since the MarkupContainer (in this case a Page) is already constructed and initialized by onBeginRequest(), the child for each tag should be available in the container. Once the Component is retrieved, it's render() method is called.

If no component can be retrieved for a given id in the markup stream, a chain of IComponentResolver objects in the Application is consulted. If one of the resolvers can resolve the id, it may actually add a component to the component hierarchy during rendering. However, such an action is special purpose and internal to Wicket and IComponentResolver is not intended for use beyond the existing AutoComponentResolver resolver that handles <wicket:component> tags and the AutoLinkResolver which creates automatic page links. The component hierarchy changes that these resolvers make are handled using special internal methods and should not be used as a general extension point for modifying Pages during rendering, which is illegal to do outside of the Wicket core.

Component.render() follows these steps to render a component:

  1. Determine component visibility. If the component is not visible, the RequestCycle's Response is changed to NullResponse.getInstance(), which is a Response implementation that simply discards its output.
  2. Component.onRender() is called to allow the Component's rendering implementation to actually render the Component.
  3. Any Component models are detached to reduce the size of the Component hierarchy in case it is replicated across a cluster.

The implementation of onRender() can really be anything that writes to the Response, but it typically is not overridden. The default
implementation of onRender() in MarkupContainer simply calls:

	protected void onRender()
	{
		renderAll(findMarkupStream());
	}

which renders the markup in the container. The implementation of onRender() in WebComponent and WebMarkupContainer calls a different method that is tuned to rendering reusable components rather than containers full of arbitrary markup:

	protected void onRender()
	{
		renderComponent(findMarkupStream());
	}

The renderComponent() method gets a mutable copy of the next Tag in the markup stream for the component and calls onComponentTag(Tag) to allow the subclass to modify the tag. Once the subclass has changed the tag, it is written out to the Response with renderComponentTag(Tag) and the markup stream is advanced to the next tag. Next onComponentTagBody() is called, passing in the MarkupStream and the ComponentTag that was written out as the opening tag. This allows the component to do whatever it needs to do to produce a body for the component tag. One operation the subclass can call in onComponentTagBody() is Component.replaceComponentTagBody(), which replaces the markup inside the component's body with an arbitrary String. Finally, the framework writes out any appropriate closing tag for the component's open tag.

Rendering to a string

For rendering a complete page to a string, see this article.

For rendering just a Panel to a string, see Rendering Panel to a String#render-panel-string.