Question

During my battle with tapestry 5 I created some setup which does not work, and I don't know why. I found few work-arounds, but still I would like to know why initial idea failed.

I have parent abstract page class with application-wide auth procedure:

public abstract class AuthPage {
    @SessionState
    protected UserAuth user;


    public Object onActivate(){
        if(user==null)
            return LoginForm.class;
        else if(user.getLoggedIn().equals(Boolean.FALSE))
            return LoginForm.class;
        else
            return null;
    }
}

Then I have index page class, using auth class as aprent:

public class Index extends AuthPage
{

}

This part works smoohtly - when user SSO is initialized then I got Index content, otherwise it goes to LoginForm. Now the problematic part - Index uses a layout component which takes care of showing personalized header and menu. Its logic looks like that:

public class Layout extends AuthPage
{  
    @Property
    private Boolean loggedIn;

    @Property
    private String userName;

    @SetupRender
    public boolean checkNames(){
        if(user==null){
            loggedIn = false;
            userName = "unlogged";
        }
        else if(user.getLoggedIn().equals(Boolean.FALSE)){
            loggedIn=false;
            userName = "unlogged";
        }
        else{
            loggedIn = true;
            userName = this.user.getUsername();
        }

        return true;
    }
}

The idea was simple - session object user from AuthPage should be available in Layout, and used on setup-render stage to get user name and rising the flag for rendering menu etc. From my point of view everything should work, but in practice Layout class didn't get user object from session (despite that it was initialized for sure, because Index renders its content).

So my question is - why Layout class don't see UserAuth object stored in session, but gets it as null instead?

************ little update:

I've refactore layout to that shape:

public class Layout
{
    @SessionState
    protected UserAuth user;

    @Property
    private Boolean loggedIn;

    @Property
    private String userName;

    @SetupRender
    public boolean checkNames(){
        if(user==null){
             loggedIn = false;
             userName = "unlogged";
        }
        else if(user.getLoggedIn().equals(Boolean.FALSE)){
             loggedIn=false;
             userName = "unlogged";
        }
        else{
             loggedIn = true;
             userName = this.user.getUsername();
        }

        return true;
    }
}

and it works as I want - Layout (executet from Index page as component) takes user attribute from session, performs checkNames and sets up all properties properly. For me there is no technical difference between initial and second implementation, but somehow when user is defined in parent class is always set to null (no matter what is stored in session). The question is - why it works that way?

Was it helpful?

Solution 3

Ok, I solved the problem! Answer is a little bit unexpected for me, but well - everything seems to work fine now. The trick is the way I was refering to the user attribue ot AuthPage class. I used

this.user

to refere to it from child classes. It turned out that I've got it as null everywhere, even in pages (I had an impression that it worked correctly in Index page, but in fact it was just used in AuthPage class). The solution was to refere by:

super.user

When I switched to such referencing style suddenly every page and component started to work properly and got correct values from session. I'll just take it as it is, but if someone knows why it works that way and no other - I'll appreciate sharing this knowledge with me.

OTHER TIPS

Layout is a component, not a page, and onActivate() is page event which won't be fired when the Layout component renders. For a component (Layout) to extend a page (AuthPage) does not make sense. I'm surprised that Tapestry allows it to tell the truth.

On another note, Tapestry has so many features (including filters, class transformations and mixins) that inheritance is almost always not required. Although quite complex, you might find the diagram at the bottom of this page useful. In particular you may be interested in the ComponentRequestFilters and PageRenderRequestFilters.

Here's a couple of options for securing pages:

  1. Howard Lewis Ship's blog - Howard is the creator of Tapestry
  2. Tynamo tapestry security

What version of tapestry are you using? In tapestry 5.3.1 and earlier, instance variables must be private. Only version 5.3.2+ supports protected and package private.

http://tapestry.apache.org/page-and-component-classes-faq.html#PageAndComponentClassesFAQ-Whydomyinstancevariableshavetobeprivate%3F

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top