Reputation: 1345
I have a tapestry page in which I have two onActivate() methods with different parameters.
// both the methods are called in this case
void onActivate(String filterSetJson) {
schema = getSchema();
if (ValueHelper.isDefined(filterSetJson) && !filterSetJson.equals("all")) {
setFilterSet( filterSetJson );
}
else {
setFilterSet("{}"); // Empty filter set
}
this.loadedTagSummary = false;
sortOrderForTags="count";
sortOrderForTypes="count";
}
void onActivate(String filterSetJson, int pageCount) {
//onActivate( filterSetJson );
this.pageCount = pageCount;
}
Sometimes this pages is invoked with two arguments, sometimes with one. The problem is that when the page is invoked with two parameters, both onActivate() methods are called. Only the method which accepts two parameters should be called.
As suggested in link below, I modified code to have just one onActivate() method which accepts EventContext as a parameter. http://apache-tapestry-mailing-list-archives.1045711.n5.nabble.com/Multiple-onActivate-methods-td2434897.html#a2434901
So the modified code is as follows.
// the following method is called twice in this case
Object onActivate(EventContext eContext){
int paramCount = eContext.getCount();
if( paramCount == 0 ) return true;
String filterSetJson = eContext.get(String.class, 0);
if( paramCount > 1 ){
int pageCount = eContext.get(Integer.class, 1);
this.pageCount = pageCount;
}
schema = getSchema();
if (ValueHelper.isDefined(filterSetJson) && !filterSetJson.equals("all")) {
setFilterSet( filterSetJson );
}
else {
setFilterSet("{}"); // Empty filter set
}
this.loadedTagSummary = false;
sortOrderForTags="count";
sortOrderForTypes="count";
return true;
}
Now, the problem is that onActivate() is still called twice. Once the parameters are present and the other time there are no parameters(I think the EventContext is empty this time). Therefore I had to add the check for parameters and return if they are not present. This avoids the whole code being executed twice but is still not a clean fix. I don't understand why the method is called twice. I have considered following potential reasons as suggested in some mailing list posts.
1: I am sure there is no image on page being given a relative path. All images are loaded with 'context'
2: There is no super class implementing onActivate() method. It is only present in this class.
Interestingly as suggested in link below, if I return true from both onActivate() methods, then only one method is called and the problem is fixed! http://apache-tapestry-mailing-list-archives.1045711.n5.nabble.com/T5-onActivate-called-twice-td2428923.html
This is the code which works fine.
// only one method is called in this case. This is the correct behavior
Object onActivate(String filterSetJson) {
schema = getSchema();
if (ValueHelper.isDefined(filterSetJson) && !filterSetJson.equals("all")) {
setFilterSet( filterSetJson );
}
else {
setFilterSet("{}"); // Empty filter set
}
this.loadedTagSummary = false;
sortOrderForTags="count";
sortOrderForTypes="count";
return true;
}
Object onActivate(String filterSetJson, int pageCount) {
//onActivate( filterSetJson );
this.pageCount = pageCount;
return true;
}
I can live with this solution but I don't understand what is happening here. Can anyone throw light on why both onActivate() methods are called when they don't return true or why onActivate(EventContext eContext) is called twice?
The other reason for posting this question is to document this for myself and for others since I have spent a lot of time in this issue.
Tapestry version is 5.3
Upvotes: 1
Views: 1705
Reputation: 27994
Please read the page here, in particular
A good "rule of thumb" is to use onActivate(...) and onPassivate() for no more than receiving and returning the activation context.
You should be careful with onActivate
as it can be called at times you may not expect (for instance when rendering a pagelink
). Your onActivate
method should be 'dumb' and simply store the values, nothing more. Put your logic in another event (eg setupRender).
I also seem to remember some strange logic in tapestry where it will call all onActivate()
methods with equal to or less than the number of page activation context variables on the URL.
I'd either:
1) Have a single onActivate(EventContext)
method to store the values. Move any logic to setupRender
.
2) Use @PageActivationContext
and setupRender
@PageActivationContext(index=0)
private String filterSetJson;
@PageActivationContext(index=1)
private Integer pageCount;
void setupRender() {
if (pageCount == null) {
...
} else {
...
}
}
Note: Multiple @PageActivationContext
is a recently new feature
These two options are roughly equivelant.
Upvotes: 1