Wicket
  1. Wicket
  2. WICKET-4009

Page Lock on Browser Back Button after Page Expiry

    Details

    • Type: Bug Bug
    • Status: Resolved
    • Priority: Major Major
    • Resolution: Fixed
    • Affects Version/s: 1.5-RC7
    • Fix Version/s: 1.5.1
    • Component/s: wicket
    • Labels:
      None
    • Environment:
      Wicket version: 1.5-RC7
      java version "1.6.0_25"
      Java(TM) SE Runtime Environment (build 1.6.0_25-b06)
      Java HotSpot(TM) Client VM (build 20.0-b11, mixed mode, sharing)

      Server: GlassFish 3.1.1

      Description

      In the attached quickstart, after page expiry and browser back navigation, a server error occurs such as:

      "failed to acquire lock to page 0, attempted for 1 minutes out of allowed 1 minute"
      This appears to be related to request logging, but I have seen other strange errors without request logging such as

      org.apache.wicket.request.handler.ComponentNotFoundException: Could not find component 'form' on page 'class web.page.ExpiredPage

      also with browser history back navigation.

      I have seen none of these errors in Wicket 1.4. I guess the reason for not having seen this before it that http cache headers are different in 1.5.

      1. quickStart.zip
        12 kB
        bernard
      2. pageManagerPatch.txt
        3 kB
        Andrea Del Bene
      3. pageManagerPatch.txt
        3 kB
        Andrea Del Bene

        Activity

        Hide
        bernard added a comment -

        Testcase

        Show
        bernard added a comment - Testcase
        Hide
        Martin Grigorov added a comment -

        I can't reproduce the problem with this quickstart.
        What's are the steps ?
        I wait for more than a minute but then pressing back/forward just works.

        Show
        Martin Grigorov added a comment - I can't reproduce the problem with this quickstart. What's are the steps ? I wait for more than a minute but then pressing back/forward just works.
        Hide
        Andrea Del Bene added a comment -

        Running quickstart with 'mvn jetty:run' I was able to reproduce the problem. But importing the project inside Eclipse and running it with Tomcat 6 and the last Wicket source everything went fine.

        Show
        Andrea Del Bene added a comment - Running quickstart with 'mvn jetty:run' I was able to reproduce the problem. But importing the project inside Eclipse and running it with Tomcat 6 and the last Wicket source everything went fine.
        Hide
        Andrea Del Bene added a comment -

        Even running project with RC7 but with Tomcat I wasn't able to reproduce the problem.

        Show
        Andrea Del Bene added a comment - Even running project with RC7 but with Tomcat I wasn't able to reproduce the problem.
        Hide
        bernard added a comment -

        Martin,

        wait for one minute then press the button on the page, then after receiving the expired page, press the browser back button.

        Andera,

        I get this on GlassFish. To get started with it quickly, you may want to download NetBeans with Java EE support which includes GlassFish. Just open the quickstart directly in NetBeans and run it from the context menu. It will prompt you with a dialog on what server to run. At the first time, you must register the installed GlassFish.

        Show
        bernard added a comment - Martin, wait for one minute then press the button on the page, then after receiving the expired page, press the browser back button. Andera, I get this on GlassFish. To get started with it quickly, you may want to download NetBeans with Java EE support which includes GlassFish. Just open the quickstart directly in NetBeans and run it from the context menu. It will prompt you with a dialog on what server to run. At the first time, you must register the installed GlassFish.
        Hide
        Andrea Del Bene added a comment -

        I've not tried GlassFish yet, but I've reproduced the problem under Eclipse with this plugin http://code.google.com/p/run-jetty-run/.
        Jetty version is 7.4.2

        Show
        Andrea Del Bene added a comment - I've not tried GlassFish yet, but I've reproduced the problem under Eclipse with this plugin http://code.google.com/p/run-jetty-run/ . Jetty version is 7.4.2
        Hide
        Andrea Del Bene added a comment -

        PageAccessSynchronizer associates page locks to a single thread. Tomcat, after session expiration, continues to serve user requests with the same thread so PageAccessSynchronizer can assign previously owned locks.
        The problem arise with web server like Jetty which seems to assign to users a new thread after session expiration. In this scenario page locks previously owned by expired session are no more unlocked.

        Possible solution:
        -Associate locks to session id and not to thread. When session expires unlock all its locks.

        What's your opinion about this Martin?

        Show
        Andrea Del Bene added a comment - PageAccessSynchronizer associates page locks to a single thread. Tomcat, after session expiration, continues to serve user requests with the same thread so PageAccessSynchronizer can assign previously owned locks. The problem arise with web server like Jetty which seems to assign to users a new thread after session expiration. In this scenario page locks previously owned by expired session are no more unlocked. Possible solution: -Associate locks to session id and not to thread. When session expires unlock all its locks. What's your opinion about this Martin?
        Hide
        Martin Grigorov added a comment - - edited

        Isn't it much easier to modify
        org.apache.wicket.page.PageAccessSynchronizer.adapt(...).new PageManagerDecorator()

        {...}

        .getPage(int) to:

        @Override
        public IManageablePage getPage(int id)
        {
        lockPage(id);
        IManageablePage page = super.getPage(id);
        if (page == null)

        { // this has to be in finally block unlockPage(id); }

        return page;
        }

        There is no unlockPage(int) but we can add it. No need to keep lock if there is no such page anymore.

        Show
        Martin Grigorov added a comment - - edited Isn't it much easier to modify org.apache.wicket.page.PageAccessSynchronizer.adapt(...).new PageManagerDecorator() {...} .getPage(int) to: @Override public IManageablePage getPage(int id) { lockPage(id); IManageablePage page = super.getPage(id); if (page == null) { // this has to be in finally block unlockPage(id); } return page; } There is no unlockPage(int) but we can add it. No need to keep lock if there is no such page anymore.
        Hide
        Andrea Del Bene added a comment -

        Yes it' much easier . I'm making some tests. If all goes well I will attach a first patch.

        Show
        Andrea Del Bene added a comment - Yes it' much easier . I'm making some tests. If all goes well I will attach a first patch.
        Hide
        Andrea Del Bene added a comment -

        I've created a patch following Martin's idea and seems to work. I attached it so you can test it.

        Show
        Andrea Del Bene added a comment - I've created a patch following Martin's idea and seems to work. I attached it so you can test it.
        Hide
        Martin Grigorov added a comment -

        In unloadPage(int) you should also check the thread like in unlockAllPages() because page id is session relative.

        Show
        Martin Grigorov added a comment - In unloadPage(int) you should also check the thread like in unlockAllPages() because page id is session relative.
        Hide
        Andrea Del Bene added a comment -

        ok, done. Tested with success on jetty 7.4.2 and GlassFish 3.1

        Show
        Andrea Del Bene added a comment - ok, done. Tested with success on jetty 7.4.2 and GlassFish 3.1
        Hide
        Andrea Del Bene added a comment -

        Martin, I've got just a question. When I click "back" button and session is expired, method PageManagerDecorator.commitRequest() is not called right?

        Show
        Andrea Del Bene added a comment - Martin, I've got just a question. When I click "back" button and session is expired, method PageManagerDecorator.commitRequest() is not called right?
        Hide
        Martin Grigorov added a comment -

        Hm. Why not ?
        Pressing back button makes a http request with older page id. If there is no such page in the page stores then null is returned by getPage(int) and PageExpiredException is thrown by PageProvider#getPageInstance(). This exception is catched by DefaultExceptionMapper and the configured IApplicationSettings#getPageExpiredErrorPage() is rendered. At the end of the request #commitRequest() should be called by RequestCycle#onDetach() (listeners.onDetach()) and PageExpiredErrorPage#onDetach() should be called (even twice - see WICKET-4012).

        Show
        Martin Grigorov added a comment - Hm. Why not ? Pressing back button makes a http request with older page id. If there is no such page in the page stores then null is returned by getPage(int) and PageExpiredException is thrown by PageProvider#getPageInstance(). This exception is catched by DefaultExceptionMapper and the configured IApplicationSettings#getPageExpiredErrorPage() is rendered. At the end of the request #commitRequest() should be called by RequestCycle#onDetach() (listeners.onDetach()) and PageExpiredErrorPage#onDetach() should be called (even twice - see WICKET-4012 ).
        Hide
        Martin Grigorov added a comment -

        Thanks, Andrea!

        Show
        Martin Grigorov added a comment - Thanks, Andrea!
        Hide
        Andrea Del Bene added a comment -

        Thank to you Martin. I made my question about expired session because I wanted to understand how we ended up with a lock left assigned.
        FOR INFORMATION: With a little more debugging I've found that when session is expired but after commitRequest(), request logger asks for page class and getPage(id) is called. So the logger should be the one who left a lock occupied and caused the bug.

        Show
        Andrea Del Bene added a comment - Thank to you Martin. I made my question about expired session because I wanted to understand how we ended up with a lock left assigned. FOR INFORMATION: With a little more debugging I've found that when session is expired but after commitRequest(), request logger asks for page class and getPage(id) is called. So the logger should be the one who left a lock occupied and caused the bug.
        Hide
        Martin Grigorov added a comment -

        Thanks Andrea!
        I just created WICKET-4029 to track that.

        Show
        Martin Grigorov added a comment - Thanks Andrea! I just created WICKET-4029 to track that.

          People

          • Assignee:
            Martin Grigorov
            Reporter:
            bernard
          • Votes:
            0 Vote for this issue
            Watchers:
            1 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved:

              Development