What is Called and When

This page demonstrates what methods are called, and when, in various situations.
It does not cover AJAX requests - they are demonstrated in AJAX: What is Called and When.

But first, a review of what a page class can do and how. It can:

And, just briefly, a couple of important things a page template can do - it can:

OK, back to the demonstration. This page provides examples of all the methods we've mentioned, and when they're called they write to the log.
For convenience, the following table shows what you would see in the logs if you configured log4j to record this page at DEBUG level:

When this page is first instantiated. pageLoaded()
When Tapestry creates a URL to this page.
Eg. when another page renders a PageLink to this page.
These are called in this page:
pageAttached()
...onPassivate()
...Tapestry creates a URL to this page
pageDetached()
In response to a page render request.
Eg. When a PageLink to this page is clicked,
or in the redirect that follows an event request.
  • The 3 onPassivate() calls are due to the EventLink, ActionLink, and Form on this page: those 3 components bubble up passivate before they render themselves. They do it to get the current activation context, which they put in the URL that they render.
  • The onPrepareForRender() and onPrepare() calls are due to the Form on this page: the Form component bubbles up prepareForRender and prepare before it renders itself.
pageAttached()
...onActivate()
...setupRender()
...beginRender()
...onPassivate()
...onPassivate()
...onPassivate()
...onPrepareForRender()
...onPrepare()
...getName()
...getMessage()
...afterRender()
...cleanupRender()
pageDetached()
Tapestry returns this page to browser
In response to an EventLink event request.
Eg. Home
pageAttached()
...onActivate()
...onGoHome()
...Tapestry creates a URL to next page
pageDetached()
Tapestry redirects browser to URL of next page
In response to ActionLink event request.
Eg. Home
pageAttached()
...onActivate()
...onAction()
...Tapestry creates a URL to next page
pageDetached()
Tapestry redirects browser to URL of next page
In response to a Form event request.
Eg. Name:
pageAttached()
...onActivate()
...onPrepareForSubmit()
...onPrepare()
...onValidateFromName()
...setName()
...onSelected()
...onValidateFromForm()
...onSuccess()
...onSubmit()
...Tapestry creates a URL to next page
pageDetached()
Tapestry redirects browser to URL of next page
message: This message is generated by getMessage().

PageAttached and PageDetached have been deprecated. However, they might be "de-deprecated" in future as discussed here.

About Thread Safety (based on an Lance's answer)
Each incoming request runs in its own thread, and Tapestry pages are singletons that are shared between threads...
So how does Tapestry avoid issues of synchronisation and conflicts of field values, ie. how does it achieve thread-safety?
The answer is byte-code manipulation: Tapestry transforms your pages and components to store their request-specific state in ThreadLocals.
In production mode, the ThreadLocal values are used. The page and component member variables are not used.
In development mode, the ThreadLocal values are used AND Tapestry mirrors them to the page and component member variables to make debugging easier.

References: Page Life Cycle, Component Rendering, Component Events, Component Parameters, EventLink, ActionLink, Form, Submit, Logging.

Home


<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<!-- We need a doctype to allow us to use special characters like &nbsp; 
     We use a "strict" DTD to make IE follow the alignment rules. -->
     
<html xmlns:t="http://tapestry.apache.org/schema/tapestry_5_4.xsd">
<body class="container">
    <h3>What is Called and When</h3>
    
    <p>This page demonstrates what methods are called, and when, in various situations.<br/>
    It does not cover AJAX requests - they are demonstrated in AJAX: What is Called and When.</p>
    
    <p>But first, a review of what a <strong>page class</strong> can do and how. It can:</p>
    <ul>
        <li><span class="what">Control rendering</span> (eg. for a page render request) with 
            <a class="link" href="http://tapestry.apache.org/component-rendering.html#ComponentRendering-RenderingPhases">
            render phase methods</a>, ie. <code>setupRender()</code>, <code>cleanupRender()</code>, etc.</li>
        <li><span class="what">Handle events</span> (ie. events bubbled up from components) with 
            <a class="link" href="http://tapestry.apache.org/component-events.html#ComponentEvents-EventHandlerMethods">
            event handler methods</a>, eg. <code>onGoHome(...)</code>, <code>onPrepareForSubmit()</code>.</li>
        <li><span class="what">Expose data</span> to its template, with 
            properties, eg. <code>getFirstName()</code>, <code>setFirstName(...)</code>, or <code>@Property</code>.</li>
        <li><span class="what">Receive its context</span> from a page render request or component event request, with an 
            <a class="link" href="http://tapestry.apache.org/page-navigation.html#PageNavigation-Pageactivation">
            activate event handler</a>, ie. <code>onActivate(...)</code>.</li>
        <li><span class="what">Return its context</span>, which Tapestry uses to generate a request URL to it, with a 
            <a class="link" href="http://tapestry.apache.org/page-navigation.html#PageNavigation-PageRenderRequests">
            passivate event handler</a>, ie. <code>onPassivate()</code>.</li>
        <li><span class="what">React to its life cycle</span> with 
            <a class="link" href="http://tapestry.apache.org/page-life-cycle.html#PageLifeCycle-PageLifeCycleMethods">page 
            life cycle methods</a> (rarely needed), ie. <code>pageLoaded()</code>, <code>pageAttached()</code>, <code>pageDetached</code>.</li>
    </ul>
    
    <p>And, just briefly, a couple of important things a <strong>page template</strong> can do - it can:</p>
    <ul>
        <li><span class="what">Render the page's properties and resources</span>, with 
            <a class="link" href="http://tapestry.apache.org/component-templates.html#ComponentTemplates-Expansions">
            expansions</a>, eg. <code>${exampleExpansion1}</code>, <code>${exampleExpansion2}</code>.</li>
        <li><span class="what">Bind the page's properties and resources</span> to components via 
            <a class="link" href="http://tapestry.apache.org/component-parameters.html">
            parameters</a>, eg. <code>${exampleParameters1}</code>.</li>
    </ul>
                
    <p>OK, back to the demonstration. This page provides examples of all the methods we've mentioned, and when they're called they write to the log.<br/> 
    For convenience, the following table shows what you would see in the logs if you configured log4j to record this page at DEBUG level:</p>
    
    <div class="eg row">
    
        <div class="col-sm-9 col-sm-offset-1">
            <table class="table table-bordered">
                <tr>
                    <th>
                        When this page is <strong>first instantiated</strong>.
                    </th>
                    <td>
                        pageLoaded()
                    </td>
                </tr>
                <tr>
                    <th>
                        When Tapestry creates <strong>a URL to this page</strong>.<br/>
                        Eg. when another page renders a PageLink to this page.
                    </th>
                    <td>
                        <em>These are called in this page:</em><br/>
                        pageAttached()<br/>
                        ...onPassivate()<br/>
                        <em>...Tapestry creates a URL to this page</em><br/>
                        pageDetached()<br/>
                    </td>
                </tr>
                <tr>
                    <th>
                        In response to a <strong>page render request</strong>.<br/>
                        Eg. When a PageLink to this page is clicked, <br/>
                        or in the redirect that follows an event request.<br/>
                        <ul>
                            <li>The 3 <em>onPassivate()</em> calls are due to the EventLink, ActionLink, and Form on this page: those 3 components 
                                bubble up <em>passivate</em> before they render themselves. They do it to get the current activation context, which 
                                they put in the URL that they render.</li>
                            <li>The <em>onPrepareForRender()</em> and <em>onPrepare()</em> calls are due to the Form on this page: the Form component 
                                bubbles up <em>prepareForRender</em> and <em>prepare</em> before it renders itself.</li>
                        </ul>
                    </th>
                    <td>
                        pageAttached()<br/>
                        ...onActivate()<br/>
                        ...setupRender()<br/>
                        ...beginRender()<br/>
                        ...onPassivate()<br/>
                        ...onPassivate()<br/>
                        ...onPassivate()<br/>
                        ...onPrepareForRender()<br/>
                        ...onPrepare()<br/>
                        ...getName()<br/>
                        ...getMessage()<br/>
                        ...afterRender()<br/>
                        ...cleanupRender()<br/>
                        pageDetached()<br/>
                        <em>Tapestry returns this page to browser</em>
                    </td>
                </tr>
                <tr>
                    <th>
                        In response to an <strong>EventLink</strong> event request.<br/>
                        Eg. <t:eventlink event="goHome">Home</t:eventlink>
                    </th>
                    <td>
                        pageAttached()<br/>
                        ...onActivate()<br/>
                        ...onGoHome()<br/>
                        <em>...Tapestry creates a URL to next page</em><br/>
                        pageDetached()<br/>
                        <em>Tapestry redirects browser to URL of next page</em>
                    </td>
                </tr>
                <tr>
                    <th>
                        In response to <strong>ActionLink</strong> event request.<br/>
                        Eg. <t:actionlink t:id="toHome">Home</t:actionlink>
                    </th>
                    <td>
                        pageAttached()<br/>
                        ...onActivate()<br/>
                        ...onAction()<br/>
                        <em>...Tapestry creates a URL to next page</em><br/>
                        pageDetached()<br/>
                        <em>Tapestry redirects browser to URL of next page</em>
                    </td>
                </tr>
                <tr>
                    <th>
                        <t:form t:id="form">
                            In response to a <strong>Form</strong> event request.
                            <div class="form-group form-inline">
                                Eg. Name: 
                                <t:textfield t:id="name"/>
                                <t:submit/>
                            </div>
                        </t:form>
                    </th>
                    <td>
                        pageAttached()<br/>
                        ...onActivate()<br/>
                        ...onPrepareForSubmit()<br/>
                        ...onPrepare()<br/>
                        ...onValidateFromName()<br/>
                        ...setName()<br/>
                        ...onSelected()<br/>
                        ...onValidateFromForm()<br/>
                        ...onSuccess()<br/>
                        ...onSubmit()<br/>
                        <em>...Tapestry creates a URL to next page</em><br/>
                        pageDetached()<br/>
                        <em>Tapestry redirects browser to URL of next page</em>
                    </td>
                </tr>
            </table>
        
            message: ${message}
        </div>
        
    </div>
    
    <p><a href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/annotations/PageAttached.html">PageAttached</a> and 
    <a href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/annotations/PageDetached.html">PageDetached</a> 
    have been deprecated. However, they might be "de-deprecated" in future 
    <a href="http://tapestry.1045711.n5.nabble.com/Which-phase-of-page-lifecycle-will-not-occur-when-we-access-page-2nd-time-td5718142.html#none">
    as discussed here</a>.</p>
    
    <p><strong>About Thread Safety</strong> (based on an <a href="http://tapestry.1045711.n5.nabble.com/Which-phase-of-page-lifecycle-will-not-occur-when-we-access-page-2nd-time-td5718142.html#none">Lance's answer</a>)<br/>
    Each incoming request runs in its own thread, and Tapestry pages are singletons that are shared between threads...<br/>
    So how does Tapestry avoid issues of synchronisation and conflicts of field values, ie. how does it achieve thread-safety?<br/>
    The answer is byte-code manipulation: Tapestry transforms your pages and components to store their request-specific state in ThreadLocals.<br/> 
    <strong>In production mode</strong>, the ThreadLocal values are used. The page and component member variables are not used.<br/> 
    <strong>In development mode</strong>, the ThreadLocal values are used AND Tapestry mirrors them to the page and component member variables to make debugging easier.</p>
    
    References: 
    <a href="http://tapestry.apache.org/page-life-cycle.html">Page Life Cycle</a>, 
    <a href="http://tapestry.apache.org/component-rendering.html">Component Rendering</a>, 
    <a href="http://tapestry.apache.org/component-events.html">Component Events</a>, 
    <a href="http://tapestry.apache.org/component-parameters.html">Component Parameters</a>, 
    <a href="http://tapestry.apache.org/5.4/apidocs/org/apache/tapestry5/corelib/components/EventLink.html">EventLink</a>, 
    <a href="http://tapestry.apache.org/5.4/apidocs/org/apache/tapestry5/corelib/components/ActionLink.html">ActionLink</a>, 
    <a href="http://tapestry.apache.org/5.4/apidocs/org/apache/tapestry5/corelib/components/Form.html">Form</a>, 
    <a href="http://tapestry.apache.org/5.4/apidocs/org/apache/tapestry5/corelib/components/Submit.html">Submit</a>, 
    <a href="http://tapestry.apache.org/logging.html">Logging</a>.<br/><br/>
    
    <t:pagelink page="Index">Home</t:pagelink><br/><br/>
    
    <t:tabgroup>
        <t:sourcecodetab src="/web/src/main/java/jumpstart/web/pages/examples/navigation/WhatIsCalledAndWhen.tml"/>
        <t:sourcecodetab src="/web/src/main/java/jumpstart/web/pages/examples/navigation/WhatIsCalledAndWhen.java"/>
        <t:sourcecodetab src="/web/src/main/resources/META-INF/assets/css/examples/whatiscalledandwhen.css"/>
    </t:tabgroup>
</body>
</html>


package jumpstart.web.pages.examples.navigation;

import jumpstart.web.pages.Index;

import org.apache.tapestry5.annotations.Import;
import org.apache.tapestry5.ioc.annotations.Inject;
import org.slf4j.Logger;

@Import(stylesheet="css/examples/whatiscalledandwhen.css")
public class WhatIsCalledAndWhen {
    
    // Screen fields

    private String name;

    // Generally useful bits and pieces

    @Inject
    private Logger logger;

    // The code

    void pageLoaded() {
        logger.debug("   ");
        logger.debug("pageLoaded()");
    }

    void pageAttached() {
        logger.debug("   ");
        logger.debug("pageAttached()");
    }

    void pageDetached() {
        logger.debug("pageDetached()");
    }

    void onActivate() {
        logger.debug("...onActivate()");
    }

    void onPassivate() {
        logger.debug("...onPassivate()");
    }

    void setupRender() {
        logger.debug("...setupRender()");
    }

    void beginRender() {
        logger.debug("...beginRender()");
    }

    void afterRender() {
        logger.debug("...afterRender()");
    }

    void cleanupRender() {
        logger.debug("...cleanupRender()");
    }

    Object onGoHome() {
        logger.debug("...onGoHome()");
        return Index.class;
    }

    Object onAction() {
        logger.debug("...onAction()");
        return Index.class;
    }

    void onPrepareForRender() {
        logger.debug("...onPrepareForRender()");
    }

    void onPrepare() {
        logger.debug("...onPrepare()");
    }

    void onPrepareForSubmit() {
        logger.debug("...onPrepareForSubmit()");
    }

    void onValidateFromName() {
        logger.debug("...onValidateFromName()");
    }

    void onSelected() {
        logger.debug("...onSelected()");
    }

    void onValidateFromForm() {
        logger.debug("...onValidateFromForm()");
    }

    void onSuccess() {
        logger.debug("...onSuccess()");
    }

    void onFailure() {
        logger.debug("...onFailure()");
    }

    Object onSubmit() {
        logger.debug("...onSubmit()");
        return Index.class;
    }

    public String getName() {
        logger.debug("...getName()");
        return name;
    }

    public void setName(String name) {
        logger.debug("...setName()");
        this.name = name;
    }

    public String getMessage() {
        logger.debug("...getMessage()");
        return "This message is generated by getMessage().";
    }
    
    public String getExampleExpansion1() {
        return "${firstName}";
    }
    
    public String getExampleExpansion2() {
        return "${context:images/icon.png}";
    }
    
    public String getExampleParameters1() {
        return "<t:TextField value=\"firstName\"/>";
    }
}


.eg {
                margin: 20px 0;
}

table {
                background-color: rgb(244,248,250);
}

th {
                width: 300px;
                font-weight: normal;
}

td {
                width: 300px;
                font-weight: normal;
}

table>tbody>tr:last-child {
                border-bottom: 1px solid #dddddd;
}

#name {
                width: 40%;
}