Upgrading from Tapestry 3.0

One goal of Tapestry 4.0 is to make upgrading from release 3.0 as painless as possible.

Tapestry 4.0 still supports the Tapestry 3.0 DTDs (with minor exceptions).

Defining the servlet path

In Tapestry 3.0, the framework could automatically determine the servlet path (used when constructing new URLs), because there was only a single mapping. The convention was to map the servlet to "/app", but any path-based mapping would automatically work.

Because of friendly URLs , there are any number of possible servlet mappings in Tapestry 4.0, so you must inform Tapestry what the correct mapping is. It is necessary to define, to Tapestry, what this mapping is, using the org.apache.tapestry.servlet-path configuration property .

Defining Engine Services

Tapestry 3.0 allowed engine services to be defined in the application specification using a <service> element. This is no longer supported in the 4.0 DTD.

Engine services are now defined using HiveMind, in the tapestry.services.ApplicationServices configuration point. The following is the chart service from the Workbench example:

  <contribution configuration-id="tapestry.services.ApplicationServices">
    <service name="chart" object="service:Chart"/>
  </contribution>

  <service-point id="Chart" interface="org.apache.tapestry.engine.IEngineService">
    <invoke-factory>
      <construct class="chart.ChartService">
        <set-object property="exceptionReporter" value="infrastructure:requestExceptionReporter"/>
        <set-object property="response" value="infrastructure:response"/>
        <set-object property="linkFactory" value="infrastructure:linkFactory"/>
      </construct>
    </invoke-factory>
  </service-point>

The <service> element in a Tapestry 3.0 DTD is now ignored .

The IEngineService interface has changed in non-backwards compatible ways. If your application created custom engine services, you will have to make changes to your code. If your custom service was based on the org.apache.tapestry.engine.AbstractService class, that class has been removed so you will have significant rewrites. As a suggested course of action, find the service that the original service was based on, and build a new service based on that Tapestry service. For example, if the original service was based on org.apache.tapestry.asset.AssetService , then get the source for the AssetService, and model your service after the new implementation.

Component Parameters

Tapestry 4.0 has greatly streamlined component parameters .

Parameter Type

In Tapestry 3.0, the <parameter> element included a type attribute. This has been removed in Tapestry 4.0.

The parameter type is now determined from the Java class, by examining the accessor methods for the property.

Tapestry 3.0 required an exact match on values bound to parameters. The bound value had to be assignable to the parameter's type. In Tapestry 4.0, parameters include built-in coercion ; Tapestry will attempt to coerce the value extracted from the bound property into the correct type. This is especially useful when using literal bindings for numeric properties. For example, an HTML template may specify a numeric value to an attribute as a simple string:

  <span jwcid="@MyComponent" intParam="50"/>

The type of the parameter is determined from the accessor method:

public abstract class MyComponent . . .

  public abstract int getIntParam();

Tapestry will convert the string value to an integer automatically.

The coercion rules are driven by a number of configuration points and services, starting with the tapestry.coerce.ValueConverter service.

Parameter Direction

In Tapestry 3.0, it was necessary to inform Tapestry of how and when a component parameter property was accessed -- this was parameter direction. Parameter direction is now ignored; Tapestry 4.0 now generates smart, caching accessor methods for parameter properties that work properly in all cases. In effect, all parameters are now of direction auto (but its a smarter, more flexible version of direction auto than was available in Tapestry 3.0).

This may be of concern if your component used the custom parameter direction. In Tapestry 3.0, direction custom meant that your code would directly access the IBinding object for the parameter, and no property for the parameter would be created. In Tapestry 4.0, a property will be created ... even if you continue to use the 3.0 DTD and specify direction custom.

Warning:

You should search for all component parameters that use direction custom and update the Java class.

For example, if you had a Tapestry 3.0 specification for a listener parameter:

  <parameter name="listener" direction="custom" type="org.apache.tapestry.IActionListener"/>  

Then your 3.0 source code might look like:

  public abstract IBinding getListenerBinding();
  
  public void someMethod(. . .)
  {
    IBinding binding = getListenerBinding();
    
    if (binding != null)
    {
      IActionListener listener = (IActionListener) binding.getObject("listener", IActionListener.class);
      
      if (listener != null)
        listener.actionTriggered(this, cycle);
    }
    
    . . .      

In Tapestry 4.0, the specification is much simpler:

  <parameter name="listener"/>

As is the Java code:

  public abstract IActionListener getListener();
  
  public void someMethod(. . .)
  {
    IActionListener listener = getListener();
    
    if (listener != null)
      listener.actionTriggered(this, cycle);
  }
  
  . . .

Tapestry takes care of de-referencing the binding (if the parameter is bound), along with type checks or coercions.

Accessing binding objects

In Tapestry 3.0, it was possible to access a IBinding object for a parameter by defining an additional property in your component's Java code:

  public abstract IBinding getListenerBinding();

This is no longer supported; the correct way to obtain a binding object is via the getBinding() method.

Note:

Because of the other improvements to parameters, it is virtually never necessary to obtain a binding object.

Default value

In the Tapestry 3.0 DTD, the optional default-value attribute was used to provide an OGNL expression to use for a parameter, if the parameter is not otherwise bound. In the Tapestry 4.0 DTD, the default-value attribute is a binding reference . The following are equivalent:

  <parameter name="foo" type="int" default-value="bar.baz"/>  <!-- 3.0 -->
  
  <parameter name="foo" default-value="bar.baz"/>             <!-- 4.0 -->
  <parameter name="bar" type="java.lang.String" 
    default-value="messages.getMessage('default-bar')"/>      <!-- 3.0 -->
  
  <parameter name="bar" default-value="message:default-bar"/> <!-- 4.0 --> 

Inherited binding

Tapestry 3.0 included an <inherited-binding> element, this was a way to directly pass the IBinding object for a component parameter to a parameter of a nested component. This is no longer supported in Tapestry 4.0; instead, the property for the component parameter should be bound to the nested component parameter:


  <!-- 3.0 -->
  
  <parameter name="itemCount" type="int"/>

  <component id="nested" type="Nested">
    <inherited-binding name="count" parameter-name="itemCount"/>
  </component>
  
  <!-- 4.0 -->
  
  <parameter name="itemCount"/>
  
  <component id="nested" type="Nested">
    <binding name="count" value="itemCount"/>
  </component>

Warning:

inherited-binding may make a comeback in Tapestry 4.0!

Specified Properties

Property specifications in Tapestry 4.0 have been simplified. The specification element has changed from <property-specification> to the simpler, <property> .

In Tapestry 3.0, it was necessary to specify the type of the property; this is no longer necessary or possible. The type attribute has been removed, and the type is determined from the Java code (and defaults to Object if the Java code does not define abstract accessors).

In addition, any abstract properties in the Java code will be converted into transient properties, even if there is no matching <property> element. Typically, the <property> element is only used when the property is either not referenced inside Java code (such as a listener method), or when when the property must be persistent.

In the 3.0 DTDs, properties could have an initial value set. The initial-value attribute was an OGNL expression used to initial the property when the page is first constructed, and when the page is detached (at the end of a request cycle). The initial value may instead be specified as the enclosed character data of the <property-specification> element.

Using the 4.0 DTDs, this is still true, but the initial-value attribute (or the enclosed character data) is a binding reference with a default prefix of "ognl:".

Managed beans

The <bean> element is used to define managed beans. In Tapestry 3.0, it could contain <set-property> and <set-message-property> elements to configure the properties of the bean.

In Tapestry 4.0, these two elements have been replaced by the <set> element, which uses a binding reference to provide the value.

Dependency Changes

Part of the transition to Tapestry 4.0, and targetting (in a later release) a minimum JDK of 1.5, is the removal of support for the Jakarta commons-lang library. commons-lang defined an Enum class that makes it impossible to compile code for JDK 1.5 ("enum" is a reserved word in JDK 1.5). With the loss of that dependency, so goes org.apache.tapestry.form.EnumPropertySelectionModel, an IPropertySelectionModel implementation.

Other code changes

A number of more subtle, and more rarely used, changes exist between the 3.0 and 4.0 releases.

The contract for ISpecificationResolverDelegate has changed. The specifications returned by the delegate are now cached by Tapestry exactly as if they had been read from files on the classpath or web context.

Changes to Components

Image and Rollover

The border parameter of the Image and Rollover components has been removed, for XHTML compliance. You may still specify a value for border as an informal parameter ... or better yet, handle this using CSS.