Philippe,
The problem you are seeing is not related to properties being initialized out
of order. The @If component only evaluates its condition during render and
saves the result in a hidden form field. When the form rewinds, it uses the
value saved during render. In your case, the myProp != null condition is only
evaluated during render (and is probably true at that time). During rewind, the
@If condition is still true no matter what the value of myProp is.
To fix this, you need to add a volative=true parameter to the @If component, to
force it to evaluate its condition at all times. But then you might get
StaleLinkException problems...
Another way is to derive your own GenericLink component, that doesn't render
during rewind:
protected void renderComponent(IMarkupWriter writer,
IRequestCycle cycle)
{
+ if (cycle.isRewinding())
+ return;
getRenderer().renderLink(writer, cycle, this);
}
Hope this helps,
Raphael Jean
EntropySoft
> -----Original Message-----
> From: news [mailto:[EMAIL PROTECTED] On Behalf Of Philippe Joly
> Sent: vendredi 10 février 2006 16:02
> To: [email protected]
> Subject: Tapestry 4 rewind system : what the hell ??
>
> Hi,
>
> Using Tapestry 4 and Tomcat 5, I have seen that "sometimes" tapestry
> behaviour
> can be very strange.
>
> I can show you an example of a code embedded in a If which is executed
> even if
> the If condition is false !
> (In fact, a component is evaluated before its parent components)
>
> Example :
>
> <span jwcid="@If" condition="ognl:myProp != null">
> it is in theory not possible to have myProp null here...
> (assuming myProp is not modified by another thread in the same time)
> </span>
>
>
> This always works fine :
>
> <span jwcid="@If" condition="ognl:myProp != null">
> <span jwcid="@Insert"
> value="ognl:'http://www.google.com?'+ myProp.something" />
> </span>
>
>
> But this can fail with error source is null for getProperty(null,
> "something") :
>
> <span jwcid="@If" condition="ognl:myProp != null">
> <a jwcid="@GenericLink"
> href="ognl:'http://www.google.com?'+ myProp.something" />
> </span>
>
> That means that sometimes (and it could depend on components you are
> using) the
> order of the sequence of the properties initialisation is not always the
> same.
> Un enclosed component may be evaluated BEFORE its parent component.
> That seems crazy to me.
>
> Indeed, in a For, you expect the current element of the loop to be set
> before executing the code inside the loop.
>
> I have created some quick and dirty example files (no database needed)
> to reproduce that problem.
>
> By default, the page works.
> But if you uncomment the GenericLink in Strange.html (line 70).
> Then you get an error when you change the value of the first select.
>
>
> My real need is to generate a GenericLink using a propery of the current
> element
> of a For.
> In my application, it always works fine. But when I use the Back button,
> and if the previous page was generated by a form.refresh,
> then I get this stupid exception when I try to submit the page again.
>
> Any idea / comment ?
>
> Thank you
> Philippe
>
> ---------------- Strange.html ----------------------------------------
> <?xml version="1.0" encoding="iso-8859-1"?>
> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
> "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
> <head>
> <title>Tapestry rewind system, you little !!</title>
> <script type="text/javascript">
> <!--
> function displayWaitMessage()
> {
> var filterDiv =
> document.getElementById("filterDiv");
> var waitDiv =
> document.getElementById("waitDiv");
>
> filterDiv.style.display = "none";
> waitDiv.style.display = "block";
> }
> // -->
> </script>
> </head>
> <body jwcid="@Body">
> <form jwcid="userForm">
> Filters : <br/>
> <select id ="selAgency"
> jwcid="agencySelect"
> onchange="displayWaitMessage();
> this.form.events.refresh()"
> />
> <div id="filterDiv">
> <select id ="selSubAgency"
> jwcid="subAgencySelect"
> />
> <br/>
> <input type ="submit"
> class ="button"
> title ="Search"
> value ="Search"
> jwcid ="searchButton" />
> </div>
> <div id="waitDiv" style="display:none">
> Please wait...
> </div>
> <br/>
> <br/>
> <table title="List of users" cellpadding="10"
> style="border-style:solid; border-size:1px">
> <caption>Users</caption>
> <thead>
> <tr>
> <th>User Id</th>
> <th>User Name</th>
> <th>Agency</th>
> <th>Sub-Agency</th>
> <th>An url</th>
> </tr>
> </thead>
> <tbody>
> <tr jwcid="@For"
> source="ognl:users"
> value="ognl:user"
> index="ognl:index"
> element="tr"
> keyExpression="id">
> <span jwcid="@If"
> condition="ognl:user
> != null">
> <td>
> <span
> jwcid="@Insert"
> value="ognl:user.id" />
> </td>
> <td>
> <span
> jwcid="@Insert"
> value="ognl:user.name" />
> </td>
> <td>
> <span
> jwcid="@Insert"
> value="ognl:user.agency.name" />
> </td>
> <td>
> <span
> jwcid="@Insert"
> value="ognl:user.subAgency.name" />
> </td>
> <td>
> <!-- HERE <a jwcid="@GenericLink"
> href="ognl:'http://www.google.com?'+ user.id"
> />
> -->
> <a
> jwcid="@Insert"
>
> value="ognl:'http://www.google.com?'+ user.id" />
> </td>
> </span>
> <span jwcid="@Else">
> <td colspan="5">Current
> user is
> null !!</td>
> </span>
> </tr>
> </tbody>
> </table>
> </form>
> </body>
> </html>
>
> ---------------- Strange.page ----------------------------------------
>
> <?xml version="1.0"?>
> <!DOCTYPE page-specification PUBLIC
> "-//Apache Software Foundation//Tapestry Specification 4.0//EN"
> "http://jakarta.apache.org/tapestry/dtd/Tapestry_4_0.dtd">
> <page-specification class="Strange">
>
> <property name="index" />
> <property name="user" />
>
> <component id="userForm" type="Form">
> <binding name="refresh" value="listener:onRefreshForm"/>
> </component>
>
> <component id="agencySelect" type="PropertySelection">
> <binding name="model" value="agencySelect"/>
> <binding name="value" value="currentSelectedAgency"/>
> </component>
>
> <component id="subAgencySelect" type="PropertySelection">
> <binding name="model" value="subAgencySelect"/>
> <binding name="value" value="currentSelectedSubAgency"/>
> </component>
>
> <component id ="searchButton" type="Submit">
> <binding name="listener" value="listener:onSearch"/>
> </component>
>
>
> </page-specification>
>
> ---------------- Strange.java ----------------------------------------
> import java.util.ArrayList;
> import java.util.List;
>
> import org.apache.tapestry.IExternalPage;
> import org.apache.tapestry.IPage;
> import org.apache.tapestry.IRequestCycle;
> import org.apache.tapestry.engine.IEngineService;
> import org.apache.tapestry.form.IPropertySelectionModel;
> import org.apache.tapestry.html.BasePage;
>
> public abstract class Strange extends BasePage implements IExternalPage {
> public abstract List getUsers();
> public abstract void setUsers(List users);
>
> public IPage onSearch() {
> System.out.println("onSearch");
> List users = StrangeUser.getUsers(getCurrentSelectedAgency(),
>
> getCurrentSelectedSubAgency());
> setUsers(users);
> return null;
> }
>
> public void onRefreshForm() {
> System.out.println("onRefreshForm");
> }
>
> public void activateExternalPage(Object[] arg0, IRequestCycle arg1)
> {
> System.out.println("activateExternalPage");
> }
>
> public abstract Agency getCurrentSelectedAgency();
> public abstract SubAgency getCurrentSelectedSubAgency();
>
> public IPropertySelectionModel getAgencySelect() {
> final List agencies = new ArrayList();
> agencies.addAll(Agency.getAgencies());
>
> Agency ALLSpecialItem = new Agency("*", "ALL");
> agencies.add(0, ALLSpecialItem);
>
> IPropertySelectionModel model = new IPropertySelectionModel()
> {
> public String getLabel(int arg0) {
> Agency agency = (Agency) agencies.get(arg0);
> return agency.getName();
> }
>
> public Object getOption(int arg0){
> return agencies.get(arg0);
> }
>
> public int getOptionCount(){
> return agencies.size();
> }
>
> public String getValue(int arg0){
> Agency agency = (Agency) agencies.get(arg0);
> return agency.getId();
> }
>
> public Object translateValue(String arg0) {
> Agency result = null;
> for(int i=0; i<agencies.size() && result==null;
> i++) {
> Agency agency = (Agency)
> agencies.get(i);
> if(agency.getId().equals(arg0)) result =
> agency;
> }
> return result;
> }
> };
> return model;
>
> }
>
> public IPropertySelectionModel getSubAgencySelect() {
> final List subAgencies = new ArrayList();
>
> Agency agency = getCurrentSelectedAgency();
> if(agency != null && !agency.getId().equals("*")) {
> subAgencies.addAll(SubAgency.getSubAgencies(agency));
> }
>
> SubAgency ALLSpecialItem = new SubAgency("*", "ALL", null);
> subAgencies.add(0, ALLSpecialItem);
>
> IPropertySelectionModel model = new IPropertySelectionModel()
> {
> public String getLabel(int arg0) {
> SubAgency sa = (SubAgency)
> subAgencies.get(arg0);
> return sa.getName();
> }
>
> public Object getOption(int arg0) {
> return subAgencies.get(arg0);
> }
>
> public int getOptionCount() {
> return subAgencies.size();
> }
>
> public String getValue(int arg0) {
> SubAgency sa = (SubAgency)
> subAgencies.get(arg0);
> return sa.getId();
> }
>
> public Object translateValue(String arg0) {
> SubAgency result = null;
> for(int i=0; i<subAgencies.size() &&
> result==null;
> i++) {
> SubAgency sa = (SubAgency)
> subAgencies.get(i);
> if(sa.getId().equals(arg0)) result = sa;
> }
> return result;
> }
> };
> return model;
> }
> }
>
> ---------------- Agency.java ----------------------------------------
>
> import java.io.Serializable;
> import java.util.ArrayList;
> import java.util.List;
>
> public class Agency implements Serializable {
>
> private static final long serialVersionUID =
> 8980683753741373155L;
>
> private static List agencies = new ArrayList();
>
> static {
> agencies.add(new Agency("0", "Agency 0"));
> agencies.add(new Agency("1", "Agency 1"));
> agencies.add(new Agency("2", "Agency 2"));
> agencies.add(new Agency("3", "Agency 3"));
> }
>
> public static List getAgencies() {
> return agencies;
> }
>
> private String id;
> private String name;
>
> public Agency() {
> super();
> }
>
> public Agency(String id, String name) {
> super();
> this.id = id;
> this.name = name;
> }
>
>
> public String getId() { return id; }
> public void setId(String id) { this.id = id; }
>
> public String getName() { return name; }
> public void setName(String name) { this.name = name; }
>
> }
>
> ---------------- SubAgency.java ---------------------------------------
>
> import java.io.Serializable;
> import java.util.ArrayList;
> import java.util.List;
>
> public class SubAgency extends Agency implements Serializable
> {
> private static final long serialVersionUID = -
> 6067658180311656578L;
>
> private Agency parentAgency;
>
> private static SubAgency[] subAgencies = {
> new SubAgency("0.0", "Sub Agency 0.0", (Agency)
> Agency.getAgencies().get(0)),
> new SubAgency("0.1", "Sub Agency 0.1", (Agency)
> Agency.getAgencies().get(0)),
> new SubAgency("1.0", "Sub Agency 1.0", (Agency)
> Agency.getAgencies().get(1)),
> new SubAgency("1.1", "Sub Agency 1.1", (Agency)
> Agency.getAgencies().get(1)),
> new SubAgency("1.2", "Sub Agency 1.2", (Agency)
> Agency.getAgencies().get(1)),
> new SubAgency("2.0", "Sub Agency 2.0", (Agency)
> Agency.getAgencies().get(2)),
> new SubAgency("2.1", "Sub Agency 2.1", (Agency)
> Agency.getAgencies().get(2)),
> new SubAgency("3.0", "Sub Agency 3.0", (Agency)
> Agency.getAgencies().get(3))
> };
>
> public SubAgency() {
> super();
> }
>
> public SubAgency(String id, String name, Agency parentAgency) {
> super(id, name);
> this.parentAgency = parentAgency;
> }
>
> public static SubAgency[] getSubAgencies() { return subAgencies; }
>
> public static List getSubAgencies(Agency agency) {
> List result = new ArrayList();
>
> for (int i = 0; agency != null && i<subAgencies.length; i++) {
> SubAgency subAgency = subAgencies[i];
> if (agency.getId().equals("*") ||
> subAgency.getParentAgency().equals(agency) )
> result.add(subAgency);
> }
> return result;
> }
>
> public Agency getParentAgency() { return parentAgency; }
> public void setParentAgency(Agency parentAgency) {
> this.parentAgency = parentAgency;
> }
> }
>
> ---------------- StrangeUser.java ----------------------------------------
>
> import java.util.ArrayList;
> import java.util.List;
>
> public class StrangeUser {
> private static final StrangeUser[] users = {
> new StrangeUser("idA", "User A",
> SubAgency.getSubAgencies()[2]),
> new StrangeUser("idB", "User B",
> SubAgency.getSubAgencies()[1]),
> new StrangeUser("idC", "User C",
> SubAgency.getSubAgencies()[0]),
> new StrangeUser("idD", "User D",
> SubAgency.getSubAgencies()[3]),
> new StrangeUser("idE", "User E",
> SubAgency.getSubAgencies()[3]),
> new StrangeUser("idF", "User F",
> SubAgency.getSubAgencies()[5])
> };
>
> public static List getUsers(Agency agency, SubAgency subAgency) {
> if(agency==null) throw new IllegalArgumentException("agency
> null");
> if(subAgency==null) throw new
> IllegalArgumentException("subAgency null");
>
> List result = new ArrayList();
> for(int i=0; i<users.length; i++) {
> StrangeUser user = users[i];
> boolean goodAgency = agency.getId().equals("*") ||
> agency.equals(user.getAgency());
> boolean goodSubAgency = subAgency.getId().equals("*") ||
>
> subAgency.equals(user.getSubAgency());
>
> if(goodAgency && goodSubAgency) {
> result.add(user);
> }
> }
> return result;
> }
>
> private String id;
> private String name;
> private Agency agency;
> private SubAgency subAgency;
>
> public StrangeUser() {
> super();
> }
> public StrangeUser(String id, String name, SubAgency subAgency) {
> super();
> this.id = id;
> this.name = name;
> this.agency = subAgency.getParentAgency();
> this.subAgency = subAgency;
> }
>
> public Agency getAgency() { return agency; }
> public void setAgency(Agency agency) { this.agency = agency; }
>
> public String getId() { return id; }
> public void setId(String id) { this.id = id; }
>
> public String getName() { return name; }
> public void setName(String name) {this.name = name; }
>
> public SubAgency getSubAgency() { return subAgency; }
> public void setSubAgency(SubAgency subAgency) { this.subAgency =
> subAgency; }
> }
>
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: [EMAIL PROTECTED]
> For additional commands, e-mail: [EMAIL PROTECTED]
---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]