Search code examples
sessionobjectcomponentstapestry

Using session objects from parent class in component


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?


Solution

  • 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.