Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Revised to reflect the migration from page pools to page singletons

...

This is somewhat revolutionary in terms of web development in Java. Using traditional servlets, or Struts, your presentation objects (Servlets, or Struts Actions, or the equivalent in other frameworks) are stateless singletons. That is, a single instance is created, and all incoming requests are threaded through that single instance.

...

Tapestry takes a very different approach.

In Tapestry, you will have many different instances of any particular page, each either in use for a single request (on a single thread), or waiting in a page pool to be used.each page is a singleton, but with a per thread map of field names & values that Tapestry invisibly manages for you.

With this approachBy reserving page instances to particular threads, all the difficult, ugly issues related to multi-threading go by the wayside. Instead, familiar, simple coding practices (using ordinary methods and fields) can be used.

However, there's a risk: it would be a disaster if data could "bleed" from one request to another. Imagine the outcome in a banking application if the first user's account number and password became the default for the second user to reach the application!

Tapestry takes special care to purge all instance variables back to their default value at the end of each request.

The end result is that all pages in the pool are entirely equivalent to each other; it doesn't matter which instance is used for processing any particular request.

Remember that the page instance is just the tip of the iceberg: a page instance encompasses the page component, its templates, all of its parameter bindings, tokens read from its template and (recursively) the same thing for all components inside the page. It adds up.

...

Info

Tapestry 5.0 and 5.1 used page pooling, rather than a singleton page with a per_thread map, to achieve the same effect.

Page Life Cycle Methods

There are a few situations where it is useful for a component to perform some operations, usually some kind of initialization or caching, based on the life cycle of the page.

The page life cycle is quite simple. When first needed, a page is loaded. Loading a page involves instantiating the components of the page and connecting them together.

Once a page is loaded, it is attached to the current request. Remember that there will be many threads, each handling its own request to the same page.

At the end of a request, after a response has been sent to the client, the page is detached from the request. This is a chance to perform any cleanup needed for the page.

As with component rendering, you have the ability to make your components "aware" of these events by identifying methods to be invoked.

Page life cycle methods should take no parameters and return void.

You have the choice of attaching an annotation to a method, or simply using the method naming conventions:

Annotation

Method Name

When Called

@PageLoaded

pageLoaded()

After the page is fully loaded

@PageAttached

pageAttached()

After the page is attached to the request. Deprecated in Tapestry 5.3

@PageDetached

pageDetached()

AFter the page is detached from the request. Deprecated in Tapestry 5.3

Comparison to JavaServer Pages

JSPs also use a caching mechanism; the JSP itself is compiled into a Java servlet class, and acts as a singleton.act as singletons. However, the individual JSP tags are pooled.

...

Note

As of 5.2, Tapestry does not employ page pooling by default

Tapestry's In Tapestry 5.0 and 5.1, a page pool is used to store page instances. The pool is "keyed" on the name of the page (such as "start") and the locale for the page (such as "en" or "fr").

...

If performance is absolute and you have lots of memory, then increase the soft and hard limit and reduce the soft wait. This encourages Tapestry to create more page instances and not wait as long to re-use existing instances.

Page Life Cycle Methods

There are a few situations where it is useful for a component to perform some operations, usually some kind of initialization or caching, based on the life cycle of the page.

The page life cycle is quite simple. When first needed, a page is loaded. Loading a page involves instantiating the components of the page and connecting them together.

Once a page is loaded, it is attached to the current request. Remember that there will be many threads, each handling its own request. In many cases, there will be multiple copies of the same page attached to different requests (and different threads). This is how Tapestry keeps you from worrying about multi-threading issues ... the objects involved in any request are reserved to just that request (and just that thread).

At the end of a request, after a response has been sent to the client, the page is detached from the request. This is a chance to perform a lot of cleanup of the page, discarding temporary objects (so that they can be reclaimed by the garbage collector) and otherwise returning the page to its pristine state. After detaching, a page is placed into the page pool, where it will await reuse for some future request (likely by a completely different user).

As with component rendering, you have the ability to make your components "aware" of these events by identifying methods to be invoked.

You have the choice of attaching an annotation to a method, or simply naming the method correctly.

Page life cycle methods should take no parameters and return void.

The annotations / method names are:

...