blob: 7cd0987579ac032bc77df7d16ca429f36a966945 [file] [log] [blame]
<!-- $Id$ -->
<!--
Copyright 2004 The Apache Software Foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<chapter id="coding">
<title>Coding Tapestry Applications</title>
<para>
After performing the design steps from the previous chapter, it
is time to start coding. The designs will imply
certain requirements for the implementations.
</para>
<section id="coding.engine">
<title>Application Engine</title>
<para>
Application engines will be serialized and de-serialized as part of
load balancing and fail over. As much as possible, attributes of the application
object should be transient. For example, the instance variable that
holds the <classname>ApplicationSpecification</classname> is transient; if
needed (after de-serialization), the engine can locate the specification from
its servlet (the servlet reads the application specification once, when it is first initialized).
</para>
<para>
This is largely not an issue, since most applications use a provided class,
such as &SimpleEngine;. Subclassing
is only necessary when the application needs a different method of instantiating the visit object, or
needs to store additional data (see <link linkend="coding.stateless" endterm="coding.stateless.title"/>).
In some cases, it is convienient to create a subclass to provide common component listener methods.
</para>
</section>
<section id="coding.visit">
<title>Visit Object</title>
<para>
The visit object will contain all the data about a client's
visit to the web application. If possible, it should have a no-arguments
constructor (this allows &SimpleEngine; to instantiate it as needed).
</para>
<para>
Keeping the size of the serialized engine small is a
good goal for overall performance and scalability, and the visit object is serialized
with the engine. During initial development, the visit
object should implement the <classname>java.io.Serializable</classname> interface.
</para>
<para>
Once the application, and the structure of the visit object, is
stable, the more efficient <classname>java.io.Externalizable</classname> interface should be implemented instead.
</para>
<para>
In addition, deferring the creation of the visit object as late as
possible is also of benefit, since this is the best way to keep the serialized engine small.
</para>
</section>
<section id="coding.stateless">
<title id="coding.stateless.title">Operating Stateless</title>
<para>
Tapestry applications can operate in a stateless mode, that is, without a &HttpSession;. The
framework automatically creates a session when needed; when the Visit object is first created,
or when any persistent page properties are changed.
</para>
<para>
Ideally, the <classname>Home</classname> page of the application should not trigger the creation of a session:
it should be careful not to create the Visit object. Remember that hits on your application will form
a curve: The <classname>Home</classname> page is at the top of the curve, and it drops of rapidly as
users penetrate deeper into the application ... how many times have you visited the front page of a web site
and gone no further?
</para>
<para>
Stateless operations will affect &ActionLink;, &DirectLink; and &Form; components on your pages. By default, they
will reject requests while the application is running stateless; the user will be redirected
to the <classname>StaleSession</classname> page. This is appropriate, since normally, the lack of a session
means that the previous session timed out and was discarded.
</para>
<para>
Each of these components has a <varname>stateful</varname> parameter which may be bound to
<literal>false</literal>. When <varname>stateful</varname> is false, the components will accept stateless
requests.
</para>
<para>
As the developer, you must keep a careful eye on what's stateful vs. stateless, and look to move
stateless data into the engine, so as to avoid creating a visit object as long as possible. For example,
the engine can resolve and store
EJB home interfaces and references to <emphasis>stateless</emphasis> session EJBs.
Even read-only database data can be stored in the engine. However, anything that is related to a particular
user must be stored in the visit object (or a persistent page property).
</para>
<para>
It is also important to not accidentally create the visit object. Every page includes
a <varname>visit</varname> property which will create the visit if it doesn't already exist. This will,
in turn, force the creation of an &HttpSession;. On the other hand, the property path
<varname>engine.visit</varname> will <emphasis>not</emphasis> create the visit object.
To avoid creating the visit, you may need to wrap some of your HTML template inside
a &Conditional; component whose condition parameter is bound to the property <varname>engine.visit</varname>.
</para>
</section>
<section id="coding.ejb">
<title>Enterprise JavaBeans Support</title>
<para>
The visit object should provide access to the most commonly
used Enterprise JavaBeans used in the application. It can provide a central location
for the common code (related to JNDI and to narrowing EJB references), rather
than have that scattered throughout the application.
</para>
<para>
It is important to remember that EJB references are not serializable.
However, it is possible to convert between an EJB reference and an EJB handle,
and handles are serializable. The visit should make any
instance variables that store EJB references transient, and should perform
extra serialization work to serialize and restore the necessary EJB handles.
</para>
<para>
Also remember that persistent page properties that are EJB references are
<emphasis>automatically</emphasis>
converted to handles when stored, and back into references when restored.
</para>
</section>
<section id="coding.page-classes">
<title>Page classes</title>
<para>
It is often useful to create one or two subclasses of
&BasePage; specific to your application.
Often your application will have a consistent navigational border on some
or all pages that can be supported by the base class.
Many applications have one set of pages that are visible
to unidentified guests, and a second section that is visible once the user logs
in. A base class for the second set of pages could override the
<function>validate()</function> method to redirect to a login page
if the user is not already logged in.
</para>
</section>
</chapter>