Upgrading from 4.0

There have been a large number of general bug fixes made in Tapestry 4.1, as well as a lot of work in the area of "ajax" support in the core framework.

This guide will attempt to highlight some of the key changes that might affect people trying to upgrade from 4.0.X to the current 4.1.X version.

Core API Changes

Many of the previously marked as deprecated for removal in Tapestry 4.1 API sections have now been removed. There is also some new functionality that many may not be aware of.

  • IRequestCycle.getRequestContext() - The old getRequestContext() method has now been removed from IRequestCycle. The proper way to get the equivalent functionality is to have the HttpServletRequest object injected in to your page/component:
    @InjectObject("service:tapestry.globals.HttpServletRequest")
    public abstract HttpServletRequest getRequest();
    
  • Autowiring services - Thanks to James Carman of HiveMind all components/pages now support autowiring of services. The rule is that you can have any service / configuration that is normally injectable via exlplicit injection configurations simply by defining a property of the same type as any of the available HiveMind services. The only caveat is that services of the same interface with more than one contributed definition can't be autowired as it would be impossible for the framework to correctly choose the right one.

    This should greatly cut down on a lot of pain of having to look up service ids in the hivedoc documentation. The injection of the HttpServletRequest outlined in the first point could be re-written as:

    public abstract HttpServletRequest getRequest();
    
  • IRequestCycle.getServiceParameters() - This method has been replaced with IRequestCycle.getListenerParameters().
  • org.apache.tapestry.event.PageRenderListener gone - PageRenderListener was split into PageBeginRenderListener and PageEndRenderListener. More on the available listener types/events can be found here.

Javascript

One of the largest changes to come about has been the general strategy in dealing with javascript inclusions as well as bundling of the Dojo javascript toolkit directly in Tapestry. More about these packaging changes can be found in the javascript guide.

  • Javascript includes - The inclusion of dojo now happens automatically if you are using the Shell component, and is in general required for Tapestry to function properly in many circumstances. If don't currently use / can't use the Shell component the same logic is also encapsulated in the ScriptIncludes component. Both components provide a variety of options allowing for client side debugging / level of debug statements / whether to use the built in dojo provided or a custom build of your own / etc..
  • form.events removed - A good majority of the core Tapestry javascript includes have either been modified or entirely replaced with new versions that are slightly easier to manage using Dojo's dynamic module inclusion capability. Almost all of the changes are backwards compatible and include new deprecation warning messages when you call one of the old Tapestry javascript functions. The new javascript API's are also heavily documented, which you can browse here.



    There is one change that is unfortunately not backwards compatible with these javascript changes, specifically dealing with the old Form.js javascript functions and how they interact with client side events for the Form component. Tapestry used to modify the client side DOM <form> element by attaching a form.events property to the object. This is no longer the case. Tapestry doesn't modify any of the DOM elements or client side events on your page anymore. While this change has resulted in much easier form handling abilities on the client side it has come with a price of breaking anyone previously relying on this functionality.
  • onload and Script templates - In previous versions of the framework Tapestry would try to ensure that javascript was written to the document body in such a way that the various sections of a Script template were written out at the correct points in the document to match the various sections of your template. This has now been modified slightly to use Dojo's event handling facilities to control this behaviour.



    Example Javascript Template:
    <script>
    <input-symbol key="component" required="yes"/>
    <let key="formObject">
        document.${component.form.name}
    </let>
    <let key="componentObject">
        ${formObject}.${component.name}
    </let>
    
    <body>
    function setFocus() {
        var inputField = ${componentObject};
        if (inputField.type != "hidden") {
            if (inputField.disabled != true) {
                inputField.focus();
            }
        } else {
             window.alert('InputFocus.script cannot set focus on a hidden field');
        }
    }
    </body>
    <initialization>
        setFocus();
    </initialization>
    </script>
    
    In previous versions of the framework the template above would be rendered out as html looking somewhat like: Previous Tapestry 4.0.X generated output:
    <html>
    <head><title>Sample</title></head>
    
    <body>
    <script type="text/javascript">
    function setFocus() {
        var inputField = document.form.field;
        if (inputField.type != "hidden") {
            if (inputField.disabled != true) {
                inputField.focus();
            }
        } else {
             window.alert('InputFocus.script cannot set focus on a hidden field');
        }
    }
    </script>
    
    <p>Hello! This is my sample page.</p>
    
    <script type="text/javascript">
    setFocus();
    </script>
    </body>
    </html>
    
    With the changes made this section would now be rendered as:

    New Tapestry 4.1.X generated output:

    <html>
    <head><title>Sample</title></head>
    
    <body>
    <script type="text/javascript">
    function setFocus() {
        var inputField = document.form.field;
        if (inputField.type != "hidden") {
            if (inputField.disabled != true) {
                inputField.focus();
            }
        } else {
             window.alert('InputFocus.script cannot set focus on a hidden field');
        }
    }
    </script>
    
    <p>Hello! This is my sample page.</p>
    
    <script type="text/javascript">
    dojo.addOnLoad(function(){
    setFocus();
    });
    </script>
    </body>
    </html>
    
  • ResponseBuilder - Don't like the way javascript is being managed? Don't want to use Dojo to manage your javascript either? That's ok too. The new response management system allows for easy contribution to many different response types in Tapestry so that you have complete control over the whole process. Currently these different types cover normal html rendering / Dojo XHR responses / JSON responses. Feel free to replace one of the existing implementations or add your own. More can be found by looking at the hivemind configuration point for it here.
  • IComponent.getClientId() - The method that was previously only available to form components has now been moved back up the chain to IComponent itself. The logic surrounding generating / working with these client ID's has also undergone extensive refactoring / improvements so that you can reliably use this method for (almost?) all of your and the core Tapestry components. This of course means that all of the core Tapestry components now output unique id="foo" attributes to support the new method as well.
Note:

The logic of what value is actually used for the id attribute varies widely depending on many different things (such as finding informal id parameters) , but all of changes are things to make it more intuitive for you / ie tries to do what you expect most of the time.

Asset Management

To be continued..

This is very much a work in progress, expect to see much more leak in over the next few weeks.