Re: Evicting the page store to force Wicket to create a new instance of a page after using the back-button
Strange, my reply on friday didn't make it to the mailing-list, so here once again: Thanks to Thorsten Schöning & subes for their feedback, even though none of the suggestions worked for my case. But it helped somehow to think about it from a different perspective. I was thinking way too complicated. (My solution is at the end fo the mail). @Thorsten: The user is not the only criteria deciding the visibility. We have several links and a lot of them have additional criteria depending on the state of the application. I am also aware of the discussion setVisible vs. isVisible. But on our project we decided to use isVisible as long as there is no significant performance penalty. Beside that after fixing the problem with the links, I could reproduce the problematic behaviour with other pages which relied on the user-object. @subes: I tried also to call invalidate() in my signOut()-method which resulted in a stackoverflow since invalidate() calls itself signout() which resulted in an endless loop. And replaceSession() was also not helpful since Wicket tried to load the last page from the page store and render the components which needed the user-object which was not there anymore. How I fixed it: In MySession I just check if the user is null and throw an PageExpiredException if it is. public User getUser() { if (user == null) { throw new PageExpiredException("No user available. Page seems to be expired."); } return user; } This way I'm always getting to the log-in page if the user-object does not exists. My initial thought was, to empty the page store so that Wicket tries to create a new instance of the page and the AuthorizeInstantiation annotation would have redirected to the login-page. Do not ask me why I was thinking so complicated in the beginning. Have a nice weekend. On 04/14/2016 03:35 PM, Joachim Rohde wrote: > Hello, > > short version of my question: how do I evict the page store to force Wicket > to create a new instance after using the > back-button? > > Longer version: > > A user is redirected after login to my main page. On my main page I have > several links in onInitialize() which > overwrites isVisible checking the role of the logged-in user, like this: > > @AuthorizeInstantiation({MyRole.sAdmin}) > public abstract class AbstractSecureBasePage extends AbstractBasePage > implements ModelDetacher { > [...] > add(new Link("managementLink") { > @Override > public void onClick() { > setResponsePage(Management.class); > } > > @Override > public boolean isVisible() { > return MySession.get().getUser().hasRole(MyRole.ADMIN); > } > }); > [...] > } > > My session: > > public class MySession extends AuthenticatedWebSession { > [...] > @Override > public void signOut() { > > user = null; > > final RequestCycle requestCycle = RequestCycle.get(); > > if (RequestCycle.get() != null && requestCycle.getRequest() != null > && > ServletWebRequest.class.isAssignableFrom(RequestCycle.get().getRequest().getClass())) > { > LOGGER.log(Level.FINE, "Invalidating HttpSession-object {0}", > ((ServletWebRequest) > RequestCycle.get().getRequest()).getContainerRequest().getSession().getId()); > ((ServletWebRequest) > RequestCycle.get().getRequest()).getContainerRequest().getSession().invalidate(); > } > super.signOut(); > } > } > > After the log-out the user is redirected back to the login-page. If the user > now click the browsers back button Wicket > tries to fetch the last page from the page store and checks the links > visibility which will result in a > NullPointerException due to the fact that getUser() returns null. > > I attempted several solutions: > > 1) Checking in every isVisible() if the user is null. This *does* work but I > have quite a lot of links and I would like > to go with this solution only if I cannot find any other. > > 2) Checking at the very beginning of onInitialize() if the user is null. This > does not work since the components are > coming from the page store and onInitialize() is not called. > > 3) Overwriting onBeforeRender() of the main page. This does not work since > it's only called if a component is visible. > > 4) My next idea was, to empty the page store within my signOut-method. > I tried several things: >getApplication().getSessionStore().destroy(); >getPageManager().clear(); >getPageManager().destroy(); >getPageManager().commitRequest(); > None of them worked. > > getPageManager().destroy(); provokes even a NullPointerException within > Wicket itself (after using the back-button): > > java.lang.NullPointerException > at > org.apache.wicket.page.PageStoreManager$SessionEntry.getPage(PageSt
Re: Evicting the page store to force Wicket to create a new instance of a page after using the back-button
Thanks to Thorsten Schöning & subes for their feedback, even though none of the suggestions worked for my case. But it helped somehow to think about it from a different perspective. I was thinking way too complicated. (My solution is at the end fo the mail). @Thorsten: The user is not the only criteria deciding the visibility. We have several links and a lot of them have additional criteria depending on the state of the application. I am also aware of the discussion setVisible vs. isVisible. But on our project we decided to use isVisible as long as there is no significant performance penalty. Beside that after fixing the problem with the links, I could reproduce the problematic behaviour with other pages which relied on the user-object. @subes: I tried also to call invalidate() in my signOut()-method which resulted in a stackoverflow since invalidate() calls itself signout() which resulted in an endless loop. And replaceSession() was also not helpful since Wicket tried to load the last page from the page store and render the components which needed the user-object which was not there anymore. How I fixed it: In MySession I just check if the user is null and throw an PageExpiredException if it is. public User getUser() { if (user == null) { throw new PageExpiredException("No user available. Page seems to be expired."); } return user; } This way I'm always getting to the log-in page if the user-object does not exists. My initial thought was, to empty the page store so that Wicket tries to create a new instance of the page and the AuthorizeInstantiation annotation would have redirected to the login-page. Do not ask me why I was thinking so complicated in the beginning. Have a nice weekend. On 04/14/2016 03:35 PM, Joachim Rohde wrote: > Hello, > > short version of my question: how do I evict the page store to force Wicket > to create a new instance after using the > back-button? > > Longer version: > > A user is redirected after login to my main page. On my main page I have > several links in onInitialize() which > overwrites isVisible checking the role of the logged-in user, like this: > > @AuthorizeInstantiation({MyRole.sAdmin}) > public abstract class AbstractSecureBasePage extends AbstractBasePage > implements ModelDetacher { > [...] > add(new Link("managementLink") { > @Override > public void onClick() { > setResponsePage(Management.class); > } > > @Override > public boolean isVisible() { > return MySession.get().getUser().hasRole(MyRole.ADMIN); > } > }); > [...] > } > > My session: > > public class MySession extends AuthenticatedWebSession { > [...] > @Override > public void signOut() { > > user = null; > > final RequestCycle requestCycle = RequestCycle.get(); > > if (RequestCycle.get() != null && requestCycle.getRequest() != null > && > ServletWebRequest.class.isAssignableFrom(RequestCycle.get().getRequest().getClass())) > { > LOGGER.log(Level.FINE, "Invalidating HttpSession-object {0}", > ((ServletWebRequest) > RequestCycle.get().getRequest()).getContainerRequest().getSession().getId()); > ((ServletWebRequest) > RequestCycle.get().getRequest()).getContainerRequest().getSession().invalidate(); > } > super.signOut(); > } > } > > After the log-out the user is redirected back to the login-page. If the user > now click the browsers back button Wicket > tries to fetch the last page from the page store and checks the links > visibility which will result in a > NullPointerException due to the fact that getUser() returns null. > > I attempted several solutions: > > 1) Checking in every isVisible() if the user is null. This *does* work but I > have quite a lot of links and I would like > to go with this solution only if I cannot find any other. > > 2) Checking at the very beginning of onInitialize() if the user is null. This > does not work since the components are > coming from the page store and onInitialize() is not called. > > 3) Overwriting onBeforeRender() of the main page. This does not work since > it's only called if a component is visible. > > 4) My next idea was, to empty the page store within my signOut-method. > I tried several things: >getApplication().getSessionStore().destroy(); >getPageManager().clear(); >getPageManager().destroy(); >getPageManager().commitRequest(); > None of them worked. > > getPageManager().destroy(); provokes even a NullPointerException within > Wicket itself (after using the back-button): > > java.lang.NullPointerException > at > org.apache.wicket.page.PageStoreManager$SessionEntry.getPage(PageStoreManager.java:203) > at > org.apache.wicket.page.PageStoreManager$PersistentRe
Re: Evicting the page store to force Wicket to create a new instance of a page after using the back-button
Guten Tag Joachim Rohde, am Donnerstag, 14. April 2016 um 15:35 schrieben Sie: > 1) Checking in every isVisible() if the user is null. This *does* > work but I have quite a lot of links and I would like > to go with this solution only if I cannot find any other. [...] > Long story short: is there a more elegant solution to my problem > than the first solution that I've tried? I'm implementing a similar approach like you and am simply using a custom base class for my links which need to be visible by some criteria only. In this base class you can take a missing user object because of no session into account at exactly one place. Your role as the only deciding criteria for visibility or not could easily be propagated using a CTOR or such. Additionally, you should not override isVisible, but onConfigure instead and call setVisible as needed. Mit freundlichen Grüßen, Thorsten Schöning -- Thorsten Schöning E-Mail: thorsten.schoen...@am-soft.de AM-SoFT IT-Systeme http://www.AM-SoFT.de/ Telefon...05151- 9468- 55 Fax...05151- 9468- 88 Mobil..0178-8 9468- 04 AM-SoFT GmbH IT-Systeme, Brandenburger Str. 7c, 31789 Hameln AG Hannover HRB 207 694 - Geschäftsführer: Andreas Muchow - To unsubscribe, e-mail: users-unsubscr...@wicket.apache.org For additional commands, e-mail: users-h...@wicket.apache.org
Re: Evicting the page store to force Wicket to create a new instance of a page after using the back-button
Or you are just missing a call to "Session.get().invalidate()" despite calling "((ServletWebRequest) RequestCycle.get().getRequest( )).getContainerRequest().getSession().invalidate();" on logout. 2016-04-14 15:59 GMT+02:00 subes : > Hi, > > I had a similar problem while developing the model aware page cache in the > NoWicket framework. I used a page factory wrapper to control when a new > page or an old page is required. > > https://github.com/subes/invesdwin-nowicket/blob/master/invesdwin-nowicket-parent/invesdwin-nowicket/src/main/java/de/invesdwin/nowicket/application/filter/internal/ModelCacheUsingPageFactory.java > > Dunno if it completely matches your requirement, but I remember that > fiddling with the PageStore directly was to no avail, so I had to get to a > step before the page store was queried. > > Though since you are talking about login, maybe you are missing the > creation of a fresh session upon login? > > See signIn method here: > https://github.com/subes/invesdwin-nowicket/blob/master/invesdwin-nowicket-parent/invesdwin-nowicket/src/main/java/de/invesdwin/nowicket/application/auth/AWebSession.java > Which calls "Session.get().replaceSession()" to start from fresh and thus > get a new page instance on next request. It is a good idea regarding > security to replace the session on signIn/signOut to prevent data leaks. > > Best regards, > Edwin > > 2016-04-14 15:35 GMT+02:00 Joachim Rohde : > >> Hello, >> >> short version of my question: how do I evict the page store to force >> Wicket to create a new instance after using the >> back-button? >> >> Longer version: >> >> A user is redirected after login to my main page. On my main page I have >> several links in onInitialize() which >> overwrites isVisible checking the role of the logged-in user, like this: >> >> @AuthorizeInstantiation({MyRole.sAdmin}) >> public abstract class AbstractSecureBasePage extends AbstractBasePage >> implements ModelDetacher { >> [...] >> add(new Link("managementLink") { >> @Override >> public void onClick() { >> setResponsePage(Management.class); >> } >> >> @Override >> public boolean isVisible() { >> return >> MySession.get().getUser().hasRole(MyRole.ADMIN); >> } >> }); >> [...] >> } >> >> My session: >> >> public class MySession extends AuthenticatedWebSession { >> [...] >> @Override >> public void signOut() { >> >> user = null; >> >> final RequestCycle requestCycle = RequestCycle.get(); >> >> if (RequestCycle.get() != null && requestCycle.getRequest() != >> null >> && >> ServletWebRequest.class.isAssignableFrom(RequestCycle.get().getRequest().getClass())) >> { >> LOGGER.log(Level.FINE, "Invalidating HttpSession-object {0}", >> ((ServletWebRequest) >> RequestCycle.get().getRequest()).getContainerRequest().getSession().getId()); >> ((ServletWebRequest) >> RequestCycle.get().getRequest()).getContainerRequest().getSession().invalidate(); >> } >> super.signOut(); >> } >> } >> >> After the log-out the user is redirected back to the login-page. If the >> user now click the browsers back button Wicket >> tries to fetch the last page from the page store and checks the links >> visibility which will result in a >> NullPointerException due to the fact that getUser() returns null. >> >> I attempted several solutions: >> >> 1) Checking in every isVisible() if the user is null. This *does* work >> but I have quite a lot of links and I would like >> to go with this solution only if I cannot find any other. >> >> 2) Checking at the very beginning of onInitialize() if the user is null. >> This does not work since the components are >> coming from the page store and onInitialize() is not called. >> >> 3) Overwriting onBeforeRender() of the main page. This does not work >> since it's only called if a component is visible. >> >> 4) My next idea was, to empty the page store within my signOut-method. >> I tried several things: >>getApplication().getSessionStore().destroy(); >>getPageManager().clear(); >>getPageManager().destroy(); >>getPageManager().commitRequest(); >> None of them worked. >> >> getPageManager().destroy(); provokes even a NullPointerException within >> Wicket itself (after using the back-button): >> >> java.lang.NullPointerException >> at >> org.apache.wicket.page.PageStoreManager$SessionEntry.getPage(PageStoreManager.java:203) >> at >> org.apache.wicket.page.PageStoreManager$PersistentRequestAdapter.getPage(PageStoreManager.java:357) >> at >> org.apache.wicket.page.AbstractPageManager.getPage(AbstractPageManager.java:82) >> at >> org.apache.wicket.page.PageManagerDecorator.getPage(PageManagerDecorator.java:50) >> at >> org.apache.wicket.page.PageAccessSynchronizer$2.getPage(PageAccessSynchronizer
Re: Evicting the page store to force Wicket to create a new instance of a page after using the back-button
Hi, I had a similar problem while developing the model aware page cache in the NoWicket framework. I used a page factory wrapper to control when a new page or an old page is required. https://github.com/subes/invesdwin-nowicket/blob/master/invesdwin-nowicket-parent/invesdwin-nowicket/src/main/java/de/invesdwin/nowicket/application/filter/internal/ModelCacheUsingPageFactory.java Dunno if it completely matches your requirement, but I remember that fiddling with the PageStore directly was to no avail, so I had to get to a step before the page store was queried. Though since you are talking about login, maybe you are missing the creation of a fresh session upon login? See signIn method here: https://github.com/subes/invesdwin-nowicket/blob/master/invesdwin-nowicket-parent/invesdwin-nowicket/src/main/java/de/invesdwin/nowicket/application/auth/AWebSession.java Which calls "Session.get().replaceSession()" to start from fresh and thus get a new page instance on next request. It is a good idea regarding security to replace the session on signIn/signOut to prevent data leaks. Best regards, Edwin 2016-04-14 15:35 GMT+02:00 Joachim Rohde : > Hello, > > short version of my question: how do I evict the page store to force > Wicket to create a new instance after using the > back-button? > > Longer version: > > A user is redirected after login to my main page. On my main page I have > several links in onInitialize() which > overwrites isVisible checking the role of the logged-in user, like this: > > @AuthorizeInstantiation({MyRole.sAdmin}) > public abstract class AbstractSecureBasePage extends AbstractBasePage > implements ModelDetacher { > [...] > add(new Link("managementLink") { > @Override > public void onClick() { > setResponsePage(Management.class); > } > > @Override > public boolean isVisible() { > return MySession.get().getUser().hasRole(MyRole.ADMIN); > } > }); > [...] > } > > My session: > > public class MySession extends AuthenticatedWebSession { > [...] > @Override > public void signOut() { > > user = null; > > final RequestCycle requestCycle = RequestCycle.get(); > > if (RequestCycle.get() != null && requestCycle.getRequest() != null > && > ServletWebRequest.class.isAssignableFrom(RequestCycle.get().getRequest().getClass())) > { > LOGGER.log(Level.FINE, "Invalidating HttpSession-object {0}", > ((ServletWebRequest) > RequestCycle.get().getRequest()).getContainerRequest().getSession().getId()); > ((ServletWebRequest) > RequestCycle.get().getRequest()).getContainerRequest().getSession().invalidate(); > } > super.signOut(); > } > } > > After the log-out the user is redirected back to the login-page. If the > user now click the browsers back button Wicket > tries to fetch the last page from the page store and checks the links > visibility which will result in a > NullPointerException due to the fact that getUser() returns null. > > I attempted several solutions: > > 1) Checking in every isVisible() if the user is null. This *does* work but > I have quite a lot of links and I would like > to go with this solution only if I cannot find any other. > > 2) Checking at the very beginning of onInitialize() if the user is null. > This does not work since the components are > coming from the page store and onInitialize() is not called. > > 3) Overwriting onBeforeRender() of the main page. This does not work since > it's only called if a component is visible. > > 4) My next idea was, to empty the page store within my signOut-method. > I tried several things: >getApplication().getSessionStore().destroy(); >getPageManager().clear(); >getPageManager().destroy(); >getPageManager().commitRequest(); > None of them worked. > > getPageManager().destroy(); provokes even a NullPointerException within > Wicket itself (after using the back-button): > > java.lang.NullPointerException > at > org.apache.wicket.page.PageStoreManager$SessionEntry.getPage(PageStoreManager.java:203) > at > org.apache.wicket.page.PageStoreManager$PersistentRequestAdapter.getPage(PageStoreManager.java:357) > at > org.apache.wicket.page.AbstractPageManager.getPage(AbstractPageManager.java:82) > at > org.apache.wicket.page.PageManagerDecorator.getPage(PageManagerDecorator.java:50) > at > org.apache.wicket.page.PageAccessSynchronizer$2.getPage(PageAccessSynchronizer.java:246) > at > org.apache.wicket.DefaultMapperContext.getPageInstance(DefaultMapperContext.java:113) > at > org.apache.wicket.core.request.handler.PageProvider.getStoredPage(PageProvider.java:299) > at > org.apache.wicket.core.request.handler.PageProvider.isNewPageInstance(PageProvider.java:211) > at > org.apache.wicket.core.request.mapper.AbstractBookmar
Evicting the page store to force Wicket to create a new instance of a page after using the back-button
Hello, short version of my question: how do I evict the page store to force Wicket to create a new instance after using the back-button? Longer version: A user is redirected after login to my main page. On my main page I have several links in onInitialize() which overwrites isVisible checking the role of the logged-in user, like this: @AuthorizeInstantiation({MyRole.sAdmin}) public abstract class AbstractSecureBasePage extends AbstractBasePage implements ModelDetacher { [...] add(new Link("managementLink") { @Override public void onClick() { setResponsePage(Management.class); } @Override public boolean isVisible() { return MySession.get().getUser().hasRole(MyRole.ADMIN); } }); [...] } My session: public class MySession extends AuthenticatedWebSession { [...] @Override public void signOut() { user = null; final RequestCycle requestCycle = RequestCycle.get(); if (RequestCycle.get() != null && requestCycle.getRequest() != null && ServletWebRequest.class.isAssignableFrom(RequestCycle.get().getRequest().getClass())) { LOGGER.log(Level.FINE, "Invalidating HttpSession-object {0}", ((ServletWebRequest) RequestCycle.get().getRequest()).getContainerRequest().getSession().getId()); ((ServletWebRequest) RequestCycle.get().getRequest()).getContainerRequest().getSession().invalidate(); } super.signOut(); } } After the log-out the user is redirected back to the login-page. If the user now click the browsers back button Wicket tries to fetch the last page from the page store and checks the links visibility which will result in a NullPointerException due to the fact that getUser() returns null. I attempted several solutions: 1) Checking in every isVisible() if the user is null. This *does* work but I have quite a lot of links and I would like to go with this solution only if I cannot find any other. 2) Checking at the very beginning of onInitialize() if the user is null. This does not work since the components are coming from the page store and onInitialize() is not called. 3) Overwriting onBeforeRender() of the main page. This does not work since it's only called if a component is visible. 4) My next idea was, to empty the page store within my signOut-method. I tried several things: getApplication().getSessionStore().destroy(); getPageManager().clear(); getPageManager().destroy(); getPageManager().commitRequest(); None of them worked. getPageManager().destroy(); provokes even a NullPointerException within Wicket itself (after using the back-button): java.lang.NullPointerException at org.apache.wicket.page.PageStoreManager$SessionEntry.getPage(PageStoreManager.java:203) at org.apache.wicket.page.PageStoreManager$PersistentRequestAdapter.getPage(PageStoreManager.java:357) at org.apache.wicket.page.AbstractPageManager.getPage(AbstractPageManager.java:82) at org.apache.wicket.page.PageManagerDecorator.getPage(PageManagerDecorator.java:50) at org.apache.wicket.page.PageAccessSynchronizer$2.getPage(PageAccessSynchronizer.java:246) at org.apache.wicket.DefaultMapperContext.getPageInstance(DefaultMapperContext.java:113) at org.apache.wicket.core.request.handler.PageProvider.getStoredPage(PageProvider.java:299) at org.apache.wicket.core.request.handler.PageProvider.isNewPageInstance(PageProvider.java:211) at org.apache.wicket.core.request.mapper.AbstractBookmarkableMapper.processHybrid(AbstractBookmarkableMapper.java:261) at org.apache.wicket.core.request.mapper.AbstractBookmarkableMapper.mapRequest(AbstractBookmarkableMapper.java:365) at org.apache.wicket.request.mapper.CompoundRequestMapper.mapRequest(CompoundRequestMapper.java:150) at org.apache.wicket.request.cycle.RequestCycle.resolveRequestHandler(RequestCycle.java:189) at org.apache.wicket.request.cycle.RequestCycle.processRequest(RequestCycle.java:219) at org.apache.wicket.request.cycle.RequestCycle.processRequestAndDetach(RequestCycle.java:293) at org.apache.wicket.protocol.http.WicketFilter.processRequestCycle(WicketFilter.java:261) at org.apache.wicket.protocol.http.WicketFilter.processRequest(WicketFilter.java:203) at org.apache.wicket.protocol.http.WicketFilter.doFilter(WicketFilter.java:284) [...] Line 203 of the PageStoreManager looks like: // not found, ask pagestore for the page return getPageStore().getPage(sessionId, id); I am not sure if here should be a null-check on getPageStore (since I have no clue what should be returned if getPageStore() returns null). Long story short: is there a more elegant solution to my problem than the first solution that I've tried? I had the hope I could em