| <?xml version="1.0" encoding="utf-8"?> |
| <!-- $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. |
| --> |
| <!DOCTYPE book PUBLIC |
| "-//OASIS//DTD DocBook XML V4.1.2//EN" |
| "http://www.oasis-open.org/docbook/xml/4.0/docbookx.dtd" [ |
| <!ENTITY % TapestryLinks SYSTEM "../common/TapestryLinks.xml"> |
| %TapestryLinks; |
| |
| ]> |
| <!-- Conventions: |
| |
| Component ids are <varname> |
| Java packages and class names are <classname> |
| Tapestry component aliases are <classname> |
| |
| In-line code snippets use <function> |
| Property paths and JavaBeans property names used <varname> |
| --> |
| <book> |
| <title>Tapestry Contributor's Guide</title> |
| <bookinfo> |
| <author> |
| <firstname>Howard</firstname> |
| <surname>Lewis Ship</surname> |
| </author> |
| <copyright> |
| <year>2002</year> |
| <year>2003</year> |
| <holder>The Apache Software Foundation</holder> |
| </copyright> |
| </bookinfo> |
| |
| <chapter id="intro"> |
| <title>Introduction</title> |
| |
| <para> |
| This document is a guide to developers who want to go |
| beyond merely developing applications <emphasis>using</emphasis> Tapestry, |
| and want to extend and improve Tapestry itself. |
| </para> |
| |
| <para> |
| Tapestry has benefitted over the first two years of its |
| development from having a focused vision and, predominantly, |
| a single developer. At the time of this writing, May 2002, |
| the Tapestry community is truly coming alive, with |
| new developers contributing fixes, components and documentation. |
| </para> |
| |
| <para> |
| The goal is to maintain the stability of Tapestry even as it |
| shifts from a one-man-show to a true community effort. Meanwhile |
| it is vitally important to not to sacrifice quality in either |
| code or <emphasis>documentation</emphasis> if Tapestry is to |
| stay on track. |
| </para> |
| |
| <para> |
| Contributing to Tapestry requires a commitment to produce excellent code, |
| examples and documentation. In fact, proper documentation in JavaDoc and |
| as updates to the tutorials and manuals represents the |
| <emphasis>dominant</emphasis> amount of effort when contributing to Tapestry. |
| </para> |
| |
| |
| </chapter> |
| |
| <chapter id="cvs"> |
| <title>CVS Access</title> |
| |
| <para> |
| Using Eclipse, obtaining the source code takes only a few steps. Tapestry |
| compiles using some libraries from &JBoss; 3.0.6 and &Jetty; 4.x which must be downloaded first. |
| </para> |
| |
| <para> |
| Eclipse must be configured with the location of JBoss, this is done from the preferences |
| panel. A new entry for <literal>JBOSS_DIR</literal> should be added. |
| </para> |
| |
| <figure> |
| <title>Eclipse: Java Classpath Preferences</title> |
| <mediaobject> |
| <imageobject> |
| <imagedata fileref="images/eclipse-classpath.png" format="PNG"/> |
| </imageobject> |
| </mediaobject> |
| </figure> |
| |
| <para> |
| Activate the CVS Repositories view and use the context menu to create a new CVS Repository location. |
| This raises a panel for defining connection information. Fill in your own |
| Jakarta name and password: |
| </para> |
| |
| <figure> |
| <title>Eclipse: New CVS Repository Location</title> |
| <mediaobject> |
| <imageobject> |
| <imagedata fileref="images/eclipse-add-repository.png" format="PNG"/> |
| </imageobject> |
| </mediaobject> |
| </figure> |
| |
| <para> |
| Next, open the new CVS Repository location. Expand the "HEAD" node, then scroll down to the "jakarta-tapestry" module. |
| Right click and select "Check Out As Project". |
| </para> |
| |
| |
| <figure> |
| <title>Eclipse: Check Out Project</title> |
| <mediaobject> |
| <imageobject> |
| <imagedata fileref="images/eclipse-check-out-project.png" format="PNG"/> |
| </imageobject> |
| </mediaobject> |
| </figure> |
| |
| <para> |
| Eclipse will checkout the latest versions of all the Tapestry code and compile it. |
| </para> |
| |
| <para> |
| You can access the Tapestry repository using command line CVS or other tools, as well. Details |
| for using command line CVS are available at the &Jakarta;. |
| </para> |
| |
| |
| </chapter> |
| |
| <chapter id="building"> |
| <title>Building Tapestry</title> |
| |
| <para> |
| Tapestry is built using &Ant; 1.5. In addition, |
| Tapestry includes the necessary control files to allow |
| development using the excellent open-source IDE, &Eclipse;. |
| </para> |
| |
| <para> |
| To perform a full build from the command line, you must have |
| JDK 1.3 or better installed, as well |
| as &JBoss; 3.0.6. |
| </para> |
| |
| <para> |
| You must create the file <filename>config/build.properties</filename> |
| (under the Tapestry root directory). This file defines a property, |
| <literal>jboss.dir</literal> that identifies the full pathname |
| to the JBoss installation and the &Jetty; installation. A sample file is provided. |
| <tip> |
| <para> |
| Be sure to use forward slashes for the path name, even |
| under Windows. Using backslashes, the escape character |
| in property files, will cause the build to fail, since |
| Ant will be using incorrect paths to the libraries obtained |
| from the JBoss distribution. |
| </para> |
| </tip> |
| </para> |
| |
| <section id="building.subprojects"> |
| <title>Tapestry Subprojects</title> |
| |
| <para> |
| The Tapestry source tree contains multiple sub-projects, each in its own subdirectory, |
| with its own Ant build file and own source code tree. |
| A root level build file (described in the <link linkend="building.targets">next section</link>) |
| performs builds over all sub-projects. |
| </para> |
| |
| <variablelist> |
| <title>Tapestry Sub-Projects</title> |
| <varlistentry> |
| <term><filename>framework</filename></term> |
| <listitem> |
| <para> |
| Contains the core framework, builds &TapestryFrameworkJar;. |
| </para> |
| </listitem> |
| </varlistentry> |
| |
| |
| <varlistentry> |
| <term><filename>contrib</filename></term> |
| <listitem> |
| <para> |
| Builds &TapestryContribJar;. |
| </para> |
| </listitem> |
| </varlistentry> |
| |
| |
| <varlistentry> |
| <term><filename>junit</filename></term> |
| <listitem> |
| <para> |
| Builds and runs JUnit tests. |
| </para> |
| </listitem> |
| </varlistentry> |
| |
| |
| <varlistentry> |
| <term><filename>examples/Workbench</filename></term> |
| <listitem> |
| <para> |
| Builds <filename>workbench.war</filename>. |
| </para> |
| </listitem> |
| </varlistentry> |
| |
| |
| |
| |
| <varlistentry> |
| <term><filename>examples/VlibBeans</filename></term> |
| <listitem> |
| <para> |
| Builds <filename>vlibbeans.jar</filename>, the EJBs used |
| by the Virtual Library demonstration. |
| </para> |
| </listitem> |
| </varlistentry> |
| |
| |
| <varlistentry> |
| <term><filename>examples/Vlib</filename></term> |
| <listitem> |
| <para> |
| Builds <filename>vlib.war</filename>, the presentation |
| layer of the Virtual Library demonstration. |
| </para> |
| </listitem> |
| </varlistentry> |
| |
| <varlistentry> |
| <term><filename>examples/VlibEAR</filename></term> |
| <listitem> |
| <para> |
| Builds <filename>vlib.ear</filename> from |
| <filename>vlibbeans.jar</filename> and |
| <filename>vlib.war</filename>. |
| </para> |
| </listitem> |
| </varlistentry> |
| |
| <varlistentry> |
| <term><filename>doc/src/DevelopersGuide</filename></term> |
| <listitem> |
| <para> |
| Builds the Tapestry Developer's Guide documentation. |
| This guide is out of date, as is being replaced. |
| </para> |
| </listitem> |
| </varlistentry> |
| |
| <varlistentry> |
| <term><filename>doc/src/UsersGuide</filename></term> |
| <listitem> |
| <para> |
| Builds the Tapestry Users' Guide (the replacement for the Developer's |
| Guide). This document is still incomplete. See, you just can't win. |
| </para> |
| </listitem> |
| </varlistentry> |
| |
| <varlistentry> |
| <term><filename>doc/src/ContributorsGuide</filename></term> |
| <listitem> |
| <para> |
| Builds this very documentation. |
| </para> |
| </listitem> |
| </varlistentry> |
| |
| <varlistentry> |
| <term><filename>doc/src/ComponentReference</filename></term> |
| <listitem> |
| <para> |
| Builds the component reference documentation. |
| </para> |
| </listitem> |
| </varlistentry> |
| </variablelist> |
| |
| </section> |
| |
| <section id="building.targets"> |
| <title>Build Targets</title> |
| |
| <para> |
| The following Ant build targets are available from the Tapestry root directory: |
| |
| <variablelist> |
| <title>Root Targets</title> |
| <varlistentry> |
| <term>clean</term> |
| <listitem> |
| <para>Cleans each sub-project and deletes derived files (such as |
| the Tapestry framework JAR and examples).</para> |
| </listitem> |
| </varlistentry> |
| |
| <varlistentry> |
| <term>clean-all</term> |
| <listitem> |
| <para> |
| As with <literal>clean</literal>, but also deletes |
| all documentation. |
| </para> |
| </listitem> |
| </varlistentry> |
| |
| <varlistentry> |
| <term>documentation</term> |
| <listitem> |
| <para> |
| Builds all documentation (see notes below). |
| </para> |
| </listitem> |
| </varlistentry> |
| |
| <varlistentry> |
| <term>install</term> |
| <listitem> |
| <para> |
| Performs a full build, by re-invoking <literal>install</literal> |
| in each sub-project. |
| </para> |
| </listitem> |
| </varlistentry> |
| |
| |
| |
| <varlistentry> |
| <term>javadoc</term> |
| <listitem> |
| <para> |
| Creates Tapestry API documentation. |
| </para> |
| </listitem> |
| </varlistentry> |
| |
| |
| <varlistentry> |
| <term>junit</term> |
| <listitem> |
| <para> |
| Runs all &JUnit; tests. |
| </para> |
| </listitem> |
| </varlistentry> |
| |
| <varlistentry> |
| <term>clover</term> |
| <listitem> |
| <para> |
| Runs all &JUnit; tests and builds a code coverage report |
| (using the Clover tool). |
| </para> |
| </listitem> |
| </varlistentry> |
| |
| |
| </variablelist> |
| |
| |
| </para> |
| |
| </section> |
| |
| <section id="building.doc-setup"> |
| <title>Documentation Setup</title> |
| |
| <para> |
| Tapestry documentation, including this manual, is also generated using Ant. Documentation |
| source is in &DocBook; XML format, and uses XSL transformation to generate readable HTML. |
| Tapestry uses &Saxon; to generate HTML documentation, and |
| &Fop; to generate PDF documentation. |
| |
| <itemizedlist> |
| |
| <listitem> |
| <para> |
| Download and unpack the &Saxon; distribution, release 6.5.2 exactly (later versions do not work). |
| </para> |
| </listitem> |
| |
| <listitem> |
| <para> |
| Obtain the latest copies of the two DocBook distributions and place the files |
| in the <filename>ext-dist</filename> directory. |
| Details are in the file |
| <filename>doc/src/common/Readme.html</filename>. |
| </para> |
| </listitem> |
| |
| <listitem> |
| <para> |
| Copy <filename>saxon.jar</filename> into the |
| Ant <filename>lib</filename> directory. |
| </para> |
| </listitem> |
| |
| <listitem> |
| <para> |
| |
| Update your |
| <envar>ANT_OPTS</envar> environment variable |
| to add the following two system properties: |
| |
| <itemizedlist> |
| <listitem> |
| <para> |
| -Djavax.xml.parsers.DocumentBuilderFactory=org.apache.crimson.jaxp.DocumentBuilderFactoryImpl |
| </para> |
| </listitem> |
| <listitem> |
| <para> |
| -Djavax.xml.parsers.SAXParserFactory=org.apache.crimson.jaxp.SAXParserFactoryImpl |
| </para> |
| </listitem> |
| </itemizedlist> |
| |
| |
| </para> |
| </listitem> |
| |
| <listitem> |
| <para> |
| Download &Fop; 0.20.4 and unpack into a permanent directory. |
| </para> |
| </listitem> |
| |
| <listitem> |
| <para> |
| Update <filename>config/build.properties</filename> and add |
| a <literal>fop.dir</literal> entry, identifying the directory |
| into which you unpacked FOP. Be sure to use an absolute |
| path name, and only forward slashes. |
| </para> |
| </listitem> |
| |
| <listitem> |
| <para> |
| Get a copy of <ulink url="http://java.sun.com/products/jimi/">JIMI</ulink> |
| (an imaging package from Sun, needed by FOP to process PNG image files), and |
| unpack it to temporary directory. |
| </para> |
| </listitem> |
| |
| <listitem> |
| <para> |
| Copy <filename>JimiProClasses.zip</filename> into the <filename><replaceable>FOP</replaceable>/lib</filename> |
| directory. |
| </para> |
| </listitem> |
| |
| </itemizedlist> |
| |
| </para> |
| |
| </section> |
| |
| <section id="building.clover-setup"> |
| <title>Clover Setup</title> |
| |
| <para> |
| <ulink url="http://www.thecortex.net/clover">Clover</ulink> is a properietary tool |
| that gathers code coverage information and generates reports from it. They |
| have kindly donated a license for Clover to the Tapestry project. |
| </para> |
| |
| <para> |
| To configure for clover: |
| <itemizedlist> |
| |
| <listitem> |
| <para> |
| Get a copy of the Clover distribution. |
| <ulink url="http://www.thecortex.net/clover/">Cortex eBusiness</ulink> has donated a copy of Clover to |
| support Tapestry. The distribution is |
| available from |
| &HowardLewisShipEmail;. |
| </para> |
| </listitem> |
| |
| <listitem> |
| <para>Extract the Clover distribution to a non-temporary directory. |
| </para> |
| </listitem> |
| |
| <listitem> |
| <para> |
| Modify <filename>config/build.properties</filename> and add an entry |
| for <literal>clover.dir</literal>. As usual, provide the absolute |
| pathname to the Clover directory, using only forward slashes. |
| </para> |
| </listitem> |
| |
| <listitem> |
| <para> |
| Copy <filename>clover.jar</filename> to the |
| <filename><replaceable>Ant</replaceable>/lib</filename> directory. |
| </para> |
| </listitem> |
| |
| </itemizedlist> |
| </para> |
| |
| |
| <para> |
| The Clover report executes from the <filename>junit</filename> directory, using the Ant |
| target <literal>clover</literal>. It builds the clover-enhanced version of the framework |
| classes, and executes the JUnit test suite twice (with all logging enabled and |
| then with all logging disabled), |
| then generates the HTML report into the |
| <filename>web/doc/clover</filename> directory. |
| </para> |
| |
| </section> |
| |
| </chapter> |
| |
| <chapter id="standards"> |
| <title>Development Standards</title> |
| |
| <para> |
| This chapter covers a number of standards, both in code and in procedure, expected by Tapestry contributors. |
| </para> |
| |
| <section id="standards.id-symbol"> |
| <title>Use of $Id$ Symbol</title> |
| |
| <para> |
| Every file checked into the CVS repository should have the $Id$ symbol inside a comment, near the top |
| of the file. The <literal>$Id$</literal> token is expanded by CVS into a useful header, identifying the revision |
| of the file, date last changed, and name of last user to change the file. |
| </para> |
| |
| <para> |
| For example, the $Id$ for this document is <literal>$Id$</literal>. |
| </para> |
| |
| </section> |
| |
| <section id="standards.typecomment"> |
| <title>Type Comment</title> |
| |
| <para> |
| Each Java file <emphasis>must</emphasis> have a complete and useful type comment. Type comments |
| must come after all <literal>import</literal> statements, and before the start of the class. |
| </para> |
| |
| <figure> |
| <title>Type Comment</title> |
| <programlisting> |
| /** |
| * <replaceable>A useful description of the class or interface, especially covering</replaceable> |
| * <replaceable>how it is used, and what other classes or interfaces it interacts with.</replaceable> |
| * |
| * @author <replaceable>Your Name</replaceable> |
| * @version $Id$ |
| * @since <replaceable>Version</replaceable> |
| */ |
| </programlisting> |
| </figure> |
| |
| <para> |
| The <replaceable>Version</replaceable> should be replaced with the numeric version number of |
| the Tapestry release the type will first appear in. This is the |
| <link linkend="releases">minor release number</link>; for example, |
| a change introduced in release <literal>2.3-beta-3</literal> |
| would be identified as <literal>2.3</literal>. |
| </para> |
| |
| </section> |
| |
| <section id="standards.javadoc"> |
| <title>JavaDoc</title> |
| |
| <para> |
| All methods should be commented, with the following exceptions: |
| |
| <itemizedlist> |
| <listitem> |
| <para> |
| Simple accessor methods with no side-effects. |
| </para> |
| </listitem> |
| |
| <listitem> |
| <para> |
| Methods that are fully described by an interface and |
| don't add any additional behaviors. |
| </para> |
| </listitem> |
| </itemizedlist> |
| </para> |
| |
| <para> |
| Parameters and return values should be identified. <literal>@throws</literal> |
| should identify when any checked exceptions are thrown; additional |
| <literal>@throws</literal> |
| entries should describe any runtime exceptions that may also be thrown. |
| </para> |
| |
| <para> |
| Methods should always include a <literal>@since</literal> entry, unless the method |
| was added as part of a new Java class or interface, in which case |
| the <literal>@since</literal> for the containing type is sufficient. |
| Use the same version number as <link linkend="standards.typecomment">type comments</link> |
| when adding individual methods. |
| </para> |
| |
| <para> |
| Try not to skimp on the comment (it is often best to write the comment before writing any code). |
| Tapestry has some of the best documentation of any open source project and that should |
| be maintained. Remember to try and answer the question <emphasis>why?</emphasis>, which is |
| always much more interesting and useful than <emphasis>how?</emphasis> or <emphasis>what?</emphasis>. |
| </para> |
| |
| <para> |
| It is appropriate to create JavaDoc comments for variables, even private variables (to at least |
| provide an <literal>@since</literal> value). |
| </para> |
| |
| <para> |
| Collections (from package <literal>java.util</literal>) should be documented to identify |
| the type of object stored, and for <classname>Map</classname> |
| the type of key. Example: <literal>List of {@link IRender}</literal>, or |
| <literal>Map of {@link IBinding} keyed on String name</literal>. |
| </para> |
| |
| <para> |
| When a method returns a collection type, the documentation should indicate if it is safe |
| for the caller to modify the collection or not. In general, it is best to always return an immutable |
| copy of a collection, but for efficiency this is not always reasonable. |
| </para> |
| |
| <para> |
| Also document any cases where a parameter is allowed to be null, or a return value may be null. |
| </para> |
| |
| <para> |
| And don't forget to make liberal use of JavaDoc links (<literal>@link</literal>) which makes the |
| documentation far easier to use. |
| </para> |
| |
| </section> |
| |
| <section id="standards.java-formatting"> |
| <title>Java Code Formatting</title> |
| |
| <para> |
| Ah, a <emphasis>religous issue</emphasis>. The most important things are to be consistent |
| (an editor that indents code for you is helpful) and to |
| <emphasis>conform to the existing style</emphasis> when editting someone else's code. |
| </para> |
| |
| <para> |
| Tapestry is formatted using <emphasis>spaces</emphasis> (not tabs), |
| and an indent of four. |
| </para> |
| |
| <para> |
| All the code currently in the repository has been formatted using the |
| Eclipse IDE. My personal preference is to include a newline before opening braces. |
| In addition, a maximum line-length of 100 characters has been used. These |
| preferences are easy to setup in Eclipse: |
| </para> |
| |
| <figure> |
| <title>Eclipse: Java Code Formatting Preferences</title> |
| <mediaobject> |
| <imageobject> |
| <imagedata fileref="images/eclipse-java-formatting.png" format="PNG"/> |
| </imageobject> |
| </mediaobject> |
| </figure> |
| |
| </section> |
| |
| <section id="standards.naming"> |
| <title>Naming Conventions</title> |
| |
| <para> |
| Standard Java guidelines are expected to be followed. |
| Class names are capitalized (example: <classname>MyClass</classname>). |
| Methods start with a lower-case character (example: <literal>myMethod</literal>). |
| </para> |
| |
| <para> |
| Static final variables used as constants |
| are in upper-case (example: <literal>MY_CONSTANT</literal>). |
| </para> |
| |
| <para> |
| Private member variables (both instance and static) are named with a leading underscore |
| (example: <literal>_myVariable</literal>). Public member variables are to be avoided. |
| </para> |
| |
| <note> |
| <title>Naming in transition</title> |
| <para> |
| I've resisted the leading underscore syntax for a long time; the rationale behind it |
| is to make it possible, at a glance, to visually seperate instance variables |
| from local variables and parameters. Previously, I've always maintained that |
| the problem was methods that were too large; lately I've changed |
| my mind ... the underscore naming helps when debugging and helps avoid |
| a number of naming collisions. |
| </para> |
| |
| <para> |
| At the time of this writing, 2.1-beta-1, very little of the code used |
| the new naming. Over time, mixed in with other bug fixes, renaming will |
| occur (&Eclipse; helps with this greatly). New code will be written to conform. |
| </para> |
| </note> |
| |
| |
| <para> |
| Interfaces in Tapestry are prefixed with the letter 'I' (example: <literal>IRequestCycle</literal>). |
| Implementations (often in a different package) |
| strip off the 'I' (example: <literal>RequestCycle</literal>). Interfaces related to JavaBean events |
| do not start with an 'I' (example: <literal>PageDetachListener</literal>). |
| </para> |
| |
| <para> |
| Base classes, classes which are concrete and functional, but often extended, are prefixed with 'Base' (example: |
| <literal>BaseComponent</literal>). Abstract classes are prefixed with 'Abstract' (example: |
| <literal>AbstractEngine</literal>). Classes which are functional and only rarely subclassed are often |
| prefixed with 'Default' (example: <literal>DefaultScriptSource</literal>). |
| </para> |
| |
| <para> |
| The base package for the framework JAR (&TapestryFrameworkJar;) is <literal>org.apache.tapestry</literal>. |
| The base package for the contrib JAR (&TapestryContribJar;) is <literal>org.apache.tapestry.contrib</literal>. |
| </para> |
| |
| </section> |
| |
| </chapter> |
| |
| <chapter id="releases"> |
| <title>Tapestry Release Numbering</title> |
| |
| <para> |
| Tapestry release numbering is relatively simple, as long as you don't look back in time |
| (the less managable numbering system used through release 2.0.5 is described shortly). |
| </para> |
| |
| <para> |
| Tapestry releases consist of a major version, a minor version and a incremental version. |
| The pattern |
| <literal> |
| <replaceable>major</replaceable>.<replaceable>minor</replaceable>-<replaceable>incremental</replaceable>-<replaceable>index</replaceable> |
| </literal> |
| is used, for example: <literal>2.1</literal>, <literal>2.2-alpha-3</literal> |
| or <literal>2.3-beta-1</literal>. |
| </para> |
| |
| <para> |
| The major version represents large-scale changes in the framework ... short of translating Tapestry |
| to another language (say, Python or Ruby), this is not likely to happen again. Tapestry |
| is currently in major release 2. |
| </para> |
| |
| |
| <para> |
| The minor version represents a milestone release, encompassing |
| the introduction of new functionality and bug fixes |
| in a stable manner. <literal>2.1</literal> or <literal>2.2</literal> would be examples |
| of milestone releases. |
| </para> |
| |
| <para> |
| An incremental release represents a transition from one milestone release to the next. |
| Incremental releases are <literal>alpha</literal>, <literal>beta</literal> or |
| <literal>rc</literal> (release candidate). |
| Typically, after a milestone release there will |
| be a series of alpha, then beta, then rc releases, leading up to |
| the next milestone release. |
| A possible sequence is <literal>2.1</literal>, <literal>2.2-alpha-1</literal>, |
| <literal>2.2-beta-1</literal>, <literal>2.2-rc-1</literal>, <literal>2.2</literal>. |
| </para> |
| |
| <para> |
| Typically, there will be several incremental releases of the same type, numbered from 1 up. |
| Alpha releases contain significant functionality changes, beta releases represent |
| bug fixes to those changes (stabilizing the changes), |
| and rc (release chandidate) releases are expected |
| to be stable versions of the next minor release (though any problems can spur further |
| release candidates). |
| </para> |
| |
| <para> |
| Through Tapestry release 2.0.5, numbering was a bit different. Under the modern scheme, |
| 2.0.1 would be named <literal>2.1-alpha-1</literal>, 2.0.2 would be <literal>2.1-alpha-2</literal>, |
| and 2.0.5 would be <literal>2.1-beta-1</literal>. Modern release numbering |
| begins with <literal>2.1-beta-2</literal> (the release immediately following 2.0.5). |
| </para> |
| |
| </chapter> |
| |
| <chapter id="procedures"> |
| <title>Development Procedures</title> |
| |
| <para> |
| This chapter defines procedures for development of Tapestry. This includes many things not directly |
| related to coding, such as documentation and interacting with the CVS repository. |
| </para> |
| |
| <section id="procedures.deprecation"> |
| <title>Deprecating methods and classes</title> |
| |
| <para> |
| Tapestry is being used by a increasingly large community of developers and it is necessary |
| that they have some stability in their development. |
| </para> |
| |
| <para> |
| To that end, classes and methods must follow a developer-friendly lifecycle. |
| If a method or class must be deleted, it should be marked as deprecated in one minor release, |
| and can be removed in the following minor release. |
| </para> |
| |
| <para> |
| For example, a method may be marked as |
| deprecated in release 2.2-alpha-1. This change isn't considered |
| "real" until release 2.2. The method can be removed any time after that, say in release 2.3-alpha-3, |
| and the removal becomes "real" in release 2.3. |
| </para> |
| |
| <para> |
| Don't simply mark a method as deprecated, give the end-developer |
| the information needed adapt their code. Use the following template |
| as part of the Javadoc comment: |
| |
| <informalexample> |
| <programlisting> |
| @deprecated To be removed in <replaceable>Version</replaceable>. |
| Use {@link <replaceable>SomeClass#someMethod(...)</replaceable>} instead. |
| </programlisting> |
| </informalexample> |
| </para> |
| |
| |
| <para> |
| It is also important for the changer to make the transition as simple as possible for |
| the end-developer. Base classes and default implementations should be changed |
| to make use of the new API in such as way that, at most, a recompile |
| of the end-developer's classes is required. |
| </para> |
| |
| <para> |
| Sometimes, changes require a lack of backwards compatibility. If |
| a method has to change and the old signature can't be maintained, then |
| simply change it ... but be sure to document the change in the |
| Tapestry release notes (<filename>web/new.html</filename>). |
| </para> |
| |
| |
| </section> |
| |
| <section id="procedures.junit"> |
| <title>JUnit Tests</title> |
| |
| |
| <para> |
| Tapestry has an excellent JUnit test suite, with code coverage |
| figures over 80% at the time of this writing (2.4-alpha-4). It is |
| <emphasis>required</emphasis> that changes to the framework |
| be accompanied by additional JUnit tests (typically, mock tests; see |
| below) to validate the changes. In addition, there is an ongoing |
| effort to fill in the gaps in the existing suite; the suite should reach |
| over 90% code coverage. |
| </para> |
| |
| <para> |
| In order to compile and run the JUnit test suite you need to download |
| <literal>junit.jar</literal> and <literal>jdom-b8.jar</literal>, |
| and place them in the <literal>ext-dist</literal> directory. |
| The official sites to download the libraries are listed in the README file |
| in that directory. |
| </para> |
| |
| <para> |
| Some of the JUnit tests now require &Jython;. You must |
| download and install Jython 2.1, |
| then configure <literal>jython.dir</literal> in <filename>config/build.properties</filename> |
| to point to the install directory. As usual, use an absolute path and forward slashes only. To run |
| the JUnit test suite within Eclipse, you must |
| set the <literal>JYTHON_DIR</literal> classpath variable. |
| </para> |
| |
| <para> |
| JUnit test source code is placed into the <filename class="directory">junit/src</filename> source tree. |
| The package name for JUnit tests is <literal>org.apache.tapestry.junit</literal>. |
| </para> |
| |
| <para> |
| Less than half of Tapestry is tested using traditional JUnit tests. The majority of JUnit testing occurs using |
| a system of mock unit tests. Mock testing involves replacing the key classes of the |
| Servlet API (<classname>HttpServletRequest</classname>, <classname>HttpSession</classname>, etc.) with |
| out own implementations, with extensions that allow for checks and validations. Instead of processing a series of |
| requests over HTTP, the requests are driven by an XML script file, which includes output checks. |
| </para> |
| |
| <para> |
| Generally, each bit of functionality can be tested using its own mini-application. |
| Create the application as |
| <filename>junit/context<replaceable>X</replaceable></filename>. This is much easier now, |
| using Tapestry 3.0 features |
| such as dynamic lookup of specifications and implicit components. |
| </para> |
| |
| <para> |
| The Mock Unit Test Suite is driven by scripts (whose structure is described below). The suite |
| searches the directory <filename>junit/mock-scripts</filename> for files with the ".xml" extension. |
| Each of these is expected to be a test script. The order in which scripts are executed is |
| arbitrary; scripts (and JUnit tests in general) should never rely on any order of execution. |
| </para> |
| |
| <para> |
| Test scripts are named <filename>Test<replaceable>Name</replaceable>.xml</filename>. |
| </para> |
| |
| |
| <note> |
| <para> |
| The XML script is not validated, and invalid elements are |
| generally ignored. The class <classname>MockTester</classname> |
| performs the test, and its capabilities are in fluxx, with |
| new capabilities being added as needed. |
| </para> |
| </note> |
| |
| <para> |
| A test script consists of an <sgmltag class="starttag">mock-test</sgmltag> |
| element. Within it, the virtual context and servlet are defined. |
| </para> |
| |
| <programlisting> |
| <![CDATA[ |
| <mock-test> |
| <context name="c6" root="context6"/> |
| |
| <servlet name="app" class="org.apache.tapestry.ApplicationServlet"> |
| <init-parameter name="org.apache.tapestry.engine-class" |
| value="org.apache.tapestry.junit.mock.c6.C6Engine"/> |
| </servlet> |
| ]]> |
| </programlisting> |
| |
| <para> |
| The name for the context becomes the leading term in any |
| generated URLs. Likewise, the servlet name becomes the second |
| term. The above example will generate URLs that reference |
| <literal>/c6/app</literal>. Specifying a <literal>root</literal> |
| for a context identifies the root context directory (beneath the top level |
| <filename>junit</filename> directory). In this example, HTML templates |
| go in <filename>context6</filename> and specifications |
| go in <filename>context6/WEB-INF</filename>. |
| </para> |
| |
| <para> |
| Following the <sgmltag class="starttag">servlet</sgmltag> |
| and <sgmltag class="starttag">context</sgmltag> elements, a series |
| of <sgmltag class="starttag">request</sgmltag> elements. Each such element |
| simulates a request. A request specifies any query parameters passed as part |
| of the request, and contains a number of assertions that test |
| either the results, generally in terms of searching for strings |
| or regular expressions within the HTML response. |
| </para> |
| |
| <programlisting> |
| <![CDATA[ |
| <request> |
| <parameter name="service" value="direct"/> |
| <parameter name="context" value="0/Home/$DirectLink"/> |
| |
| <assert-output name="Page Title"> |
| <![CDATA[ |
| <title>Persistant Page Property</title> |
| ]]>]]><![CDATA[ |
| </assert-output> |
| ]]> |
| </programlisting> |
| |
| <warning> |
| <para> |
| As in the above example, it is very important |
| that HTML tags be properly escaped with the XML CDATA construct. |
| </para> |
| </warning> |
| |
| <para> |
| Adding <literal>failover="true"</literal> to the |
| <sgmltag class="starttag">request</sgmltag> simulates a failover. The contents |
| of the &HttpSession; are serialized, |
| then deserialized. This ensures that all the data stored into the |
| &HttpSession; will survive a failover to a new server within |
| a cluster. |
| </para> |
| |
| <para> |
| All of the assertion elements expect a <literal>name</literal> |
| attribute, which is incorporated into any error message |
| if the assertion fails (that is, if the expected output |
| is not present). |
| </para> |
| |
| |
| <para> |
| The <sgmltag class="starttag">assert-output</sgmltag> element checks for the |
| presence of the contained literal output, contained within the |
| element. Leading and trailing whitespace is trimmed before |
| the check is made. |
| </para> |
| |
| <programlisting> |
| <![CDATA[ |
| <assert name="Session Attribute"> |
| request.session.getAttribute("app/Home/message").equals("Changed") |
| </assert> |
| ]]> |
| </programlisting> |
| |
| <para> |
| The <sgmltag class="starttag">assert</sgmltag> element checks |
| that the provided OGNL expression evaluates to true. |
| </para> |
| |
| <programlisting> |
| <![CDATA[ |
| <assert-regexp name="Error Message"> |
| <![CDATA[ |
| <span class="error">\s*You must enter a value for Last Name\.\s*</span> |
| ]]>]]><![CDATA[ |
| </assert-regexp> |
| ]]> |
| </programlisting> |
| |
| <para> |
| The <sgmltag class="starttag">assert-regexp</sgmltag> looks |
| for a regular expression in the result, instead of a simple literal |
| string. |
| </para> |
| |
| <programlisting> |
| <![CDATA[ |
| <assert-output-matches name="Selected Radio" subgroup="1"> |
| <![CDATA[ |
| <input type="radio" name="inputSex" checked="checked" value="(.*?)"/> |
| ]]>]]><![CDATA[ |
| <match>1</match> |
| </assert-output-matches> |
| ]]> |
| </programlisting> |
| |
| <para> |
| The <sgmltag class="starttag">assert-output-matches</sgmltag> |
| is the most complicated assertion. It contains a regular expression |
| which is evaluated. For each match, the subgroup value is extracted, |
| and compared to the next <sgmltag class="starttag">match</sgmltag> |
| value. Also, the count of matches (vs. the number of |
| <sgmltag class="stattag">match</sgmltag> elements) is checked. |
| </para> |
| |
| <programlisting> |
| <![CDATA[ |
| <assert-output-stream name="Asset Content" |
| content-type="image/gif" |
| path="foo/bar/baz.gif"/> |
| ]]> |
| </programlisting> |
| |
| <para> |
| The <sgmltag class="starttag">assert-output-stream</sgmltag> |
| element is used to compare the entire response to a static file |
| (this is normally associated with private assets). A content type |
| must be specified, as well as a relative path to a file to compare |
| against. The path is relative to the junit directory. The |
| response must match the specified content type and actual content. |
| </para> |
| |
| <programlisting> |
| <![CDATA[ |
| <assert-exception name="Exception"> |
| File foo not found. |
| </assert-exception> |
| ]]> |
| </programlisting> |
| |
| <para> |
| The <sgmltag class="starttag">assert-exception</sgmltag> element |
| is used to check when an request fails entirely (is unable to send back a |
| response). This only occurs when the application specification contains invalid |
| data (such as an incorrect class for the engine), or when the Exception page |
| is unable to execute. The body of the element is matched against the exception's |
| message property. |
| </para> |
| |
| <note> |
| <title>Force a failure, then check for correctness</title> |
| <para> |
| Sometimes the tests themselves have bugs. A useful technique is |
| to purposely break the test to ensure that it is checking for what |
| it should check, then fix the test. For example, adding <literal>XXX</literal> |
| into a <sgmltag class="starttag">assert-output</sgmltag>. Run the test suite |
| and expect a failure, then remove the <literal>XXX</literal> and |
| re-run the test, which should succeed. |
| </para> |
| </note> |
| |
| </section> |
| |
| <section id="procedures.documentation"> |
| <title>Documentation</title> |
| |
| <para> |
| Documentation is much harder than coding, but the ongoing success of Tapestry depends on maintaining |
| the quality of documentation. Tapestry documentation is written using &DocBook; XML format, using |
| XSL stylesheets to convert to final documentation. |
| </para> |
| |
| <para> |
| Changes to the framework usually require a change in documentation to the Tapestry Developer's Guide. |
| </para> |
| |
| </section> |
| |
| <section id="procedures.component-doc"> |
| <title>Component Documentation</title> |
| |
| <warning> |
| <para> |
| This section is out of date. In general, each component should |
| include a link to the Component Reference page for the component. |
| The Component Reference page has a format and content |
| similar to what's listed here. |
| </para> |
| </warning> |
| |
| <para> |
| Although there is limited documentation about components in their component specification file, that documentation |
| is designed to be a short reminder, not the complete documentation. Full documentation goes into |
| the component's Java file, as part of its type comment JavaDoc. |
| </para> |
| |
| <para> |
| Component documentation consists of a table, identifying all the formal parameters of the component. |
| In addition, a note indicating whether informal parameters are allowed, and if the component may |
| have a body (that is, wrap other components) is supplied at the end. |
| </para> |
| |
| <figure> |
| <title>Component Documentation Template</title> |
| <programlisting> |
| /** |
| * <replaceable>Type comment documentation ...</replaceable> |
| * |
| * <p><table border=1> |
| * <tr> |
| * <th>Parameter</th> |
| * <th>Type</th> |
| * <th>Direction</th> |
| * <th>Required</th> |
| * <th>Default</th> |
| * <th>Description</th> |
| * </tr> |
| * |
| * <tr> |
| * <td><replaceable>name</replaceable></td> |
| * <td><replaceable>{@link Type}</replaceable></td> |
| * <td><replaceable>in|out|in-out</replaceable></td> <co id="procedures.component-doc.direction"/> |
| * <td><replaceable>yes|no</replaceable></td> |
| * <td><replaceable>Default value</replaceable></td> <co id="procedures.component-doc.default"/> |
| * <td><replaceable>Full description</replaceable></td> |
| * </tr> |
| * |
| * ... |
| * |
| * <p>Informal parameters are <replaceable>[not]</replaceable> allowed. The component |
| * may <replaceable>[not]</replaceable> contain a body. |
| * |
| * ... |
| * |
| */ |
| </programlisting> |
| <calloutlist> |
| <callout arearefs="procedures.component-doc.direction"> |
| <para> |
| This describes how the component uses its binding. |
| <literal>in</literal> indicates the binding is read, but never updated, which is |
| the most common case. |
| <literal>out</literal> indicates the binding is updated, but not read; this is rare, but |
| does apply to some parameters of &Foreach;, for example. |
| <literal>in-out</literal> is common used with certain form parameters. |
| </para> |
| </callout> |
| |
| <callout arearefs="procedures.component-doc.default"> |
| <para> |
| If the parameter is required, then this is usually specified as &nbsp; (non-breaking space). |
| </para> |
| </callout> |
| </calloutlist> |
| |
| </figure> |
| |
| |
| <para> |
| Recently, <ulink url="../ComponentReference/index.html">seperate HTML component documentation</ulink> |
| has been created. This will be the standard location |
| for Framework component documentation. Javadoc for the |
| component should simply have a link |
| to the correct Component Reference page. |
| </para> |
| |
| <para> |
| The component reference is simply HTML (at least, for the time being). |
| There are many examples and a template available, for creating |
| new reference pages. |
| </para> |
| |
| </section> |
| |
| <section id="procedures.checkin"> |
| <title>Checkin Procedures</title> |
| |
| <para> |
| You should always follow these procedures when checking in code: |
| |
| <variablelist> |
| <varlistentry> |
| <listitem> |
| <para> |
| Run JUnit tests (ant junit) before doing a checkin. |
| </para> |
| </listitem> |
| </varlistentry> |
| |
| <varlistentry> |
| <listitem> |
| <para> |
| Build the Javadoc (ant javadoc) to ensure there are no errors introduced. |
| </para> |
| </listitem> |
| </varlistentry> |
| |
| <varlistentry> |
| <listitem> |
| <para> |
| Add a Bugzilla bug or a feature request describing the change. |
| </para> |
| </listitem> |
| </varlistentry> |
| |
| <varlistentry> |
| <listitem> |
| <para> |
| When checking code in, use the Bugzilla bug id as the checkin comment. |
| </para> |
| </listitem> |
| </varlistentry> |
| |
| </variablelist> |
| |
| </para> |
| |
| <example> |
| <title>Example checkin comment</title> |
| <programlisting> |
| [ 553310 ] Set properties from parameter bindings |
| </programlisting> |
| </example> |
| |
| |
| <para> |
| In addition, update the Tapestry release notes, the file <filename>web/new.html</filename>, |
| to identify the feature request. |
| </para> |
| |
| |
| <para> |
| If you are adding new code, please make sure that the code contains: |
| |
| <variablelist> |
| <varlistentry> |
| <listitem> |
| <para> |
| The Apache license in a comment block at the beginning. |
| </para> |
| </listitem> |
| </varlistentry> |
| |
| <varlistentry> |
| <listitem> |
| <para> |
| The $Id$ symbol as described above. |
| </para> |
| </listitem> |
| </varlistentry> |
| </variablelist> |
| |
| </para> |
| |
| <para> |
| Be very careful when checking files in that they are checked in with the correct |
| keyword substitution type. |
| Files should be either binary or text; text should be checked in with keyword |
| expansion turned on (this is the <literal>-kkv</literal> option). |
| </para> |
| |
| <para> |
| When new files are added using Eclipse, it must decide whether they are |
| binary or text. Eclipse always assumes <emphasis>binary</emphasis> |
| unless specifically informed that a file is text. Use the Team preferences |
| panel to set this. |
| </para> |
| |
| <figure> |
| <title>Eclipse: Team Preferences</title> |
| <mediaobject> |
| <imageobject> |
| <imagedata fileref="images/eclipse-team-preferences.png" format="PNG"/> |
| </imageobject> |
| </mediaobject> |
| </figure> |
| |
| <para> |
| Finally, if major changes are enacted, |
| it is good to ensure that the framework continues to be compatible |
| with the API versions declared in the User Guide. This can be verified |
| by performing the following actions: |
| |
| <variablelist> |
| <varlistentry> |
| <listitem> |
| <para> |
| Compile the framework using Java 1.2.2. |
| (e.g. by setting <literal>JAVA_HOME</literal> and running <literal>ant</literal>) |
| </para> |
| </listitem> |
| </varlistentry> |
| |
| <varlistentry> |
| <listitem> |
| <para> |
| Run the unit tests using both Java 1.3.x and 1.4.x |
| (e.g. by setting <literal>JAVA_HOME</literal> and running 'ant junit'). |
| Running the unit tests under 1.3.x would require adding |
| the <literal>Xerces</literal> libraries to the classpath |
| (e.g. to <filename>lib/ext</filename>). |
| </para> |
| </listitem> |
| </varlistentry> |
| |
| <varlistentry> |
| <listitem> |
| <para> |
| Compile with Java Servlet API 2.3 and run the unit tests |
| using Java Servlet API 2.2 |
| (e.g. by compiling, then pointing the <literal>servlet.jar</literal> setting in |
| the <filename>config/build.properties</filename> file to the |
| Java Servlet API 2.2 library and running 'ant junit') |
| </para> |
| </listitem> |
| </varlistentry> |
| </variablelist> |
| |
| </para> |
| |
| |
| |
| </section> |
| |
| |
| <section id="procedures.examples"> |
| <title>Creating Examples</title> |
| |
| <para> |
| Extending the Workbench application to demonstrate new features or components |
| is expected for any significant changes or additions to the framework, or |
| to the contrib library. |
| </para> |
| |
| </section> |
| |
| <section id="procedures.copyrights"> |
| <title>Updating Copyrights</title> |
| |
| <para> |
| All source code stored in the repository must contain the standard Apache copyright and license. A copy of the |
| license, as a comment block, is stored as <filename>support/license.txt</filename> |
| </para> |
| |
| <para> |
| Realize that you are assigning copyright to the Apache Software Foundation. |
| </para> |
| |
| <para> |
| The contents of this file can be pasted in directly before the <literal>package</literal> statement of a Java source file. |
| </para> |
| |
| <para> |
| Alternately, a <ulink url="http://www.python.org">Python</ulink> script is provided which |
| can locate all Java source files within a directory tree and ensure that the leading comment block |
| is correct. It modifies any source files where the leading comment doesn't match, but does not modify |
| any files where the leading comment matches. |
| </para> |
| |
| <para> |
| To use the script, execute the command |
| <command>python support/update-copyrights.py LICENSE.txt <replaceable>directory ...</replaceable></command>. |
| </para> |
| |
| <para> |
| You may specify any number of directories, though the script is fast enough that just using "." (for current directory) |
| is easiest. |
| </para> |
| |
| |
| |
| <warning> |
| <title>Cygwin Python</title> |
| <para> |
| On my computer (running Windows XP and/or 2000), when using the |
| <ulink url="http://sources.redhat.com/cygwin">Cygwin</ulink> |
| version of Python, it is necessary to execute the script |
| from the Bash shell, not the standard Windows command line. |
| </para> |
| </warning> |
| |
| </section> <!-- procedures.copyrights --> |
| |
| </chapter> |
| |
| </book> |