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).
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 .
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.
Tapestry 4.0 has greatly streamlined component parameters .
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.
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.
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.
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 -->
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>
inherited-binding may make a comeback in Tapestry 4.0!
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:".
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.
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.
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.